[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[tor-commits] [Git][tpo/applications/tor-browser][tor-browser-153.1.0esr-16.0-1] 6 commits: fixup! TB 27476: Implement about:torconnect captive portal within Tor Browser



Title: GitLab

morgan pushed to branch tor-browser-153.1.0esr-16.0-1 at The Tor Project / Applications / Tor Browser

Commits:

  • 6a6cb5e8
    by Henry Wilkes at 2026-08-26T12:08:36+00:00
    fixup! TB 27476: Implement about:torconnect captive portal within Tor Browser
    
    TB 45236: Make the breadcrumbs focusable and activatable with a
    keyboard.
    
    We also update the breadcrumb states to be more consistent between
    stages, and we no longer disable prior breadcrumbs during a bootstrap
    since it is safe for the user to switch back to a prior stage.
    
  • 9250f769
    by Henry Wilkes at 2026-08-26T12:08:36+00:00
    fixup! TB 27476: Implement about:torconnect captive portal within Tor Browser
    
    TB 45236: Have the "configure connection" link point to
    about:preferences to give users a hint of where they are going.
    
  • fe4fe5a2
    by Henry Wilkes at 2026-08-26T12:08:36+00:00
    fixup! TB 27476: Implement about:torconnect captive portal within Tor Browser
    
    TB 45236: Drop the wrapping <form> element.
    
    Also fix the `for` attribute to point to the `<select>` element.
    
  • 747ca252
    by Henry Wilkes at 2026-08-26T12:08:36+00:00
    fixup! TB 27476: Implement about:torconnect captive portal within Tor Browser
    
    TB 45236: Expose the progress bar to accessibility tools.
    
  • 3cb7efed
    by Henry Wilkes at 2026-08-26T12:08:36+00:00
    fixup! TB 40597: Implement TorSettings module
    
    TB 45236: Return early when Moat returns no bridges.
    
  • f54fe85b
    by Henry Wilkes at 2026-08-26T12:08:36+00:00
    fixup! TB 40597: Implement TorSettings module
    
    TB 45236: Add an option to simulate progress in simulated bootstraps.
    
    This is useful for debugging the about:torconnect page.
    
    We also lazy-load the `setTimeout` and related methods since these are
    only used for simulated scenarios.
    

4 changed files:

Changes:

  • browser/components/torconnect/content/aboutTorConnect.css
    ... ... @@ -25,42 +25,59 @@ body {
    25 25
     #breadcrumbs {
    
    26 26
       grid-area: breadcrumbs;
    
    27 27
       display: flex;
    
    28
    -  align-items: center;
    
    28
    +  gap: var(--space-large);
    
    29 29
       margin: 0 0 var(--space-xlarge) 0;
    
    30
    -}
    
    31 30
     
    
    32
    -#breadcrumbs.hidden {
    
    33
    -  visibility: hidden;
    
    31
    +  &.hide-breadcrumbs {
    
    32
    +    visibility: hidden;
    
    33
    +  }
    
    34
    +
    
    35
    +  & :is(ol, li:not([hidden])) {
    
    36
    +    display: contents;
    
    37
    +  }
    
    34 38
     }
    
    35 39
     
    
    36 40
     .breadcrumb-item,
    
    37 41
     .breadcrumb-separator {
    
    38
    -  display: flex;
    
    39
    -  margin: 0;
    
    40
    -  margin-inline-start: var(--space-large);
    
    42
    +  flex: 0 0 auto;
    
    41 43
       padding: var(--space-small);
    
    42 44
     }
    
    43 45
     
    
    44 46
     .breadcrumb-item {
    
    47
    +  display: flex;
    
    48
    +  gap: var(--space-xsmall);
    
    45 49
       align-items: center;
    
    46 50
       cursor: pointer;
    
    47 51
       color: var(--text-color);
    
    48 52
       border-radius: var(--border-radius-small);
    
    49
    -}
    
    50 53
     
    
    51
    -.breadcrumb-item:hover {
    
    52
    -  color: var(--color-accent-primary);
    
    53
    -  background-color: var(--button-background-color-hover);
    
    54
    -}
    
    54
    +  & > * {
    
    55
    +    flex: 0 0 auto;
    
    56
    +  }
    
    57
    +
    
    58
    +  &:not(.breadcrumb-disabled):hover {
    
    59
    +    color: var(--color-accent-primary);
    
    60
    +    background-color: var(--button-background-color-hover);
    
    61
    +  }
    
    62
    +
    
    63
    +  &:not(.breadcrumb-disabled):active {
    
    64
    +    color: var(--color-accent-primary-active);
    
    65
    +    background-color: var(--button-background-color-active);
    
    66
    +  }
    
    67
    +
    
    68
    +  &.breadcrumb-active {
    
    69
    +    color: var(--color-accent-primary);
    
    70
    +  }
    
    55 71
     
    
    56
    -.breadcrumb-item:active {
    
    57
    -  color: var(--color-accent-primary-active);
    
    58
    -  background-color: var(--button-background-color-active);
    
    72
    +  &.breadcrumb-disabled {
    
    73
    +    color: var(--text-color);
    
    74
    +    opacity: 0.4;
    
    75
    +    cursor: unset;
    
    76
    +  }
    
    59 77
     }
    
    60 78
     
    
    61 79
     .breadcrumb-separator {
    
    62
    -  width: var(--icon-size);
    
    63
    -  list-style-image: url("chrome://browser/content/torconnect/arrow-right.svg");
    
    80
    +  content: url("chrome://browser/content/torconnect/arrow-right.svg");
    
    64 81
     }
    
    65 82
     
    
    66 83
     .breadcrumb-separator:dir(rtl) {
    
    ... ... @@ -68,61 +85,35 @@ body {
    68 85
     }
    
    69 86
     
    
    70 87
     .breadcrumb-icon {
    
    71
    -  display: inline list-item;
    
    88
    +  width: var(--icon-size);
    
    72 89
       height: var(--icon-size);
    
    73
    -  list-style-position: inside;
    
    74 90
       -moz-context-properties: fill, stroke;
    
    75 91
       fill: currentColor;
    
    76 92
       stroke: currentColor;
    
    77 93
     }
    
    78 94
     
    
    79
    -.breadcrumb-item.active {
    
    80
    -  color: var(--color-accent-primary);
    
    81
    -}
    
    82
    -
    
    83
    -.breadcrumb-item.disabled,
    
    84
    -.breadcrumb-item.disabled:hover,
    
    85
    -.breadcrumb-item.disabled:active {
    
    86
    -  color: var(--text-color);
    
    87
    -  opacity: 0.4;
    
    88
    -  cursor: default;
    
    89
    -}
    
    90
    -
    
    91
    -.breadcrumb-item.hidden,
    
    92
    -.breadcrumb-separator.hidden {
    
    93
    -  display: none;
    
    94
    -}
    
    95
    -
    
    96 95
     #connect-to-tor {
    
    97 96
       margin-inline-start: 0;
    
    98 97
     }
    
    99 98
     
    
    100 99
     #connect-to-tor-icon {
    
    101
    -  list-style-image: url("chrome://browser/content/torconnect/tor-connect.svg");
    
    100
    +  content: url("chrome://browser/content/torconnect/tor-connect.svg");
    
    102 101
     }
    
    103 102
     
    
    104 103
     #connection-assist-icon {
    
    105
    -  list-style-image: url("chrome://browser/content/torconnect/tor-connect-broken.svg");
    
    106
    -}
    
    107
    -
    
    108
    -#try-bridge {
    
    109
    -  cursor: default;
    
    104
    +  content: url("chrome://browser/content/torconnect/tor-connect-broken.svg");
    
    110 105
     }
    
    111 106
     
    
    112 107
     #try-bridge-icon {
    
    113
    -  list-style-image: url("chrome://browser/content/torconnect/bridge.svg");
    
    108
    +  content: url("chrome://browser/content/torconnect/bridge.svg");
    
    114 109
     }
    
    115 110
     
    
    116 111
     #locationDropdownLabel.error {
    
    117 112
       color: var(--text-color-error);
    
    118 113
     }
    
    119 114
     
    
    120
    -form#locationDropdown {
    
    115
    +#regions-select {
    
    121 116
       width: 240px;
    
    122
    -}
    
    123
    -
    
    124
    -form#locationDropdown select {
    
    125
    -  width: 100%;
    
    126 117
       margin: 0;
    
    127 118
       font-weight: var(--font-weight-bold);
    
    128 119
     }
    

  • browser/components/torconnect/content/aboutTorConnect.html
    ... ... @@ -33,33 +33,43 @@
    33 33
         ></script>
    
    34 34
       </head>
    
    35 35
       <body class="onion-pattern-background">
    
    36
    -    <div id="progressBar" hidden="hidden">
    
    36
    +    <div
    
    37
    +      id="progressBar"
    
    38
    +      role="progressbar"
    
    39
    +      aria-valuenow="0"
    
    40
    +      aria-valuemin="0"
    
    41
    +      aria-valuemax="100"
    
    42
    +      aria-labelledby="tor-connect-heading"
    
    43
    +      hidden="hidden"
    
    44
    +    >
    
    37 45
           <div id="progressSolid"></div>
    
    38 46
           <div id="progressBackground"></div>
    
    39 47
           <div id="progressBarBackground"></div>
    
    40 48
         </div>
    
    41
    -    <div id="breadcrumbs" class="hidden">
    
    42
    -      <span id="connect-to-tor" class="breadcrumb-item">
    
    43
    -        <span id="connect-to-tor-icon" class="breadcrumb-icon"></span>
    
    44
    -        <span class="breadcrumb-label"></span>
    
    45
    -      </span>
    
    46
    -      <span
    
    47
    -        id="connection-assist-separator"
    
    48
    -        class="breadcrumb-separator breadcrumb-icon"
    
    49
    -      ></span>
    
    50
    -      <span id="connection-assist" class="breadcrumb-item">
    
    51
    -        <span id="connection-assist-icon" class="breadcrumb-icon"></span>
    
    52
    -        <span class="breadcrumb-label"></span>
    
    53
    -      </span>
    
    54
    -      <span
    
    55
    -        id="try-bridge-separator"
    
    56
    -        class="breadcrumb-separator breadcrumb-icon"
    
    57
    -      ></span>
    
    58
    -      <span id="try-bridge" class="breadcrumb-item">
    
    59
    -        <span id="try-bridge-icon" class="breadcrumb-icon"></span>
    
    60
    -        <span class="breadcrumb-label"></span>
    
    61
    -      </span>
    
    62
    -    </div>
    
    49
    +    <nav id="breadcrumbs">
    
    50
    +      <ol>
    
    51
    +        <li id="connect-to-tor">
    
    52
    +          <div class="breadcrumb-item" role="link" tabindex="0">
    
    53
    +            <span id="connect-to-tor-icon" class="breadcrumb-icon"></span>
    
    54
    +            <span class="breadcrumb-label"></span>
    
    55
    +          </div>
    
    56
    +        </li>
    
    57
    +        <li id="connection-assist">
    
    58
    +          <div class="breadcrumb-separator breadcrumb-icon"></div>
    
    59
    +          <div class="breadcrumb-item" role="link" tabindex="0">
    
    60
    +            <span id="connection-assist-icon" class="breadcrumb-icon"></span>
    
    61
    +            <span class="breadcrumb-label"></span>
    
    62
    +          </div>
    
    63
    +        </li>
    
    64
    +        <li id="try-bridge">
    
    65
    +          <div class="breadcrumb-separator breadcrumb-icon"></div>
    
    66
    +          <div class="breadcrumb-item" role="link" tabindex="0">
    
    67
    +            <span id="try-bridge-icon" class="breadcrumb-icon"></span>
    
    68
    +            <span class="breadcrumb-label"></span>
    
    69
    +          </div>
    
    70
    +        </li>
    
    71
    +      </ol>
    
    72
    +    </nav>
    
    63 73
         <div class="torconnect-stage-content" data-stage-name="ProviderStopped">
    
    64 74
           <img class="torconnect-icon assist-icon" alt="" />
    
    65 75
           <h1
    
    ... ... @@ -166,14 +176,12 @@
    166 176
             <button id="configureButton" hidden="true"></button>
    
    167 177
             <button id="cancelButton" hidden="true"></button>
    
    168 178
             <button id="connectButton" hidden="true" class="tor-button"></button>
    
    169
    -        <label id="locationDropdownLabel" for="">"countries"></label>
    
    170
    -        <form id="locationDropdown" hidden="true">
    
    171
    -          <select id="regions-select">
    
    172
    -            <option id="first-region-option"></option>
    
    173
    -            <optgroup id="frequent-regions-option-group"></optgroup>
    
    174
    -            <optgroup id="full-regions-option-group"></optgroup>
    
    175
    -          </select>
    
    176
    -        </form>
    
    179
    +        <label id="locationDropdownLabel" for="">"regions-select"></label>
    
    180
    +        <select id="regions-select" hidden="hidden">
    
    181
    +          <option id="first-region-option"></option>
    
    182
    +          <optgroup id="frequent-regions-option-group"></optgroup>
    
    183
    +          <optgroup id="full-regions-option-group"></optgroup>
    
    184
    +        </select>
    
    177 185
             <button id="tryBridgeButton" hidden="true" class="tor-button"></button>
    
    178 186
           </div>
    
    179 187
         </div>
    

  • browser/components/torconnect/content/aboutTorConnect.js
    ... ... @@ -42,12 +42,10 @@ class AboutTorConnect {
    42 42
             label: "#connect-to-tor .breadcrumb-label",
    
    43 43
           },
    
    44 44
           connectionAssist: {
    
    45
    -        separator: "#connection-assist-separator",
    
    46 45
             link: "#connection-assist",
    
    47 46
             label: "#connection-assist .breadcrumb-label",
    
    48 47
           },
    
    49 48
           tryBridge: {
    
    50
    -        separator: "#try-bridge-separator",
    
    51 49
             link: "#try-bridge",
    
    52 50
             label: "#try-bridge .breadcrumb-label",
    
    53 51
           },
    
    ... ... @@ -66,7 +64,6 @@ class AboutTorConnect {
    66 64
           connect: "button#connectButton",
    
    67 65
           tryBridge: "button#tryBridgeButton",
    
    68 66
           locationDropdownLabel: "#locationDropdownLabel",
    
    69
    -      locationDropdown: "form#locationDropdown",
    
    70 67
           locationDropdownSelect: "#regions-select",
    
    71 68
         },
    
    72 69
       });
    
    ... ... @@ -90,18 +87,12 @@ class AboutTorConnect {
    90 87
         connectToTorLabel: document.querySelector(
    
    91 88
           this.selectors.breadcrumbs.connectToTor.label
    
    92 89
         ),
    
    93
    -    connectionAssistSeparator: document.querySelector(
    
    94
    -      this.selectors.breadcrumbs.connectionAssist.separator
    
    95
    -    ),
    
    96 90
         connectionAssistLink: document.querySelector(
    
    97 91
           this.selectors.breadcrumbs.connectionAssist.link
    
    98 92
         ),
    
    99 93
         connectionAssistLabel: document.querySelector(
    
    100 94
           this.selectors.breadcrumbs.connectionAssist.label
    
    101 95
         ),
    
    102
    -    tryBridgeSeparator: document.querySelector(
    
    103
    -      this.selectors.breadcrumbs.tryBridge.separator
    
    104
    -    ),
    
    105 96
         tryBridgeLink: document.querySelector(
    
    106 97
           this.selectors.breadcrumbs.tryBridge.link
    
    107 98
         ),
    
    ... ... @@ -120,9 +111,6 @@ class AboutTorConnect {
    120 111
         locationDropdownLabel: document.querySelector(
    
    121 112
           this.selectors.buttons.locationDropdownLabel
    
    122 113
         ),
    
    123
    -    locationDropdown: document.querySelector(
    
    124
    -      this.selectors.buttons.locationDropdown
    
    125
    -    ),
    
    126 114
         locationDropdownSelect: document.querySelector(
    
    127 115
           this.selectors.buttons.locationDropdownSelect
    
    128 116
         ),
    
    ... ... @@ -221,7 +209,7 @@ class AboutTorConnect {
    221 209
         this.hide(this.elements.cancelButton);
    
    222 210
         this.hide(this.elements.connectButton);
    
    223 211
         this.hide(this.elements.locationDropdownLabel);
    
    224
    -    this.hide(this.elements.locationDropdown);
    
    212
    +    this.hide(this.elements.locationDropdownSelect);
    
    225 213
         this.hide(this.elements.tryBridgeButton);
    
    226 214
       }
    
    227 215
     
    
    ... ... @@ -239,33 +227,49 @@ class AboutTorConnect {
    239 227
       }
    
    240 228
     
    
    241 229
       setBreadcrumbsStatus(connectToTor, connectionAssist, tryBridge) {
    
    242
    -    this.elements.breadcrumbContainer.classList.remove("hidden");
    
    243
    -    const elems = [
    
    244
    -      [this.elements.connectToTorLink, connectToTor, null],
    
    245
    -      [
    
    246
    -        this.elements.connectionAssistLink,
    
    247
    -        connectionAssist,
    
    248
    -        this.elements.connectionAssistSeparator,
    
    249
    -      ],
    
    250
    -      [
    
    251
    -        this.elements.tryBridgeLink,
    
    252
    -        tryBridge,
    
    253
    -        this.elements.tryBridgeSeparator,
    
    254
    -      ],
    
    255
    -    ];
    
    256
    -    elems.forEach(([elem, status, separator]) => {
    
    257
    -      elem.classList.remove(BreadcrumbStatus.Hidden);
    
    258
    -      elem.classList.remove(BreadcrumbStatus.Disabled);
    
    259
    -      elem.classList.remove(BreadcrumbStatus.Active);
    
    260
    -      if (status !== "") {
    
    261
    -        elem.classList.add(status);
    
    230
    +    this.elements.breadcrumbContainer.classList.remove("hide-breadcrumbs");
    
    231
    +    for (const { listEl, status } of [
    
    232
    +      { listEl: this.elements.connectToTorLink, status: connectToTor },
    
    233
    +      { listEl: this.elements.connectionAssistLink, status: connectionAssist },
    
    234
    +      { listEl: this.elements.tryBridgeLink, status: tryBridge },
    
    235
    +    ]) {
    
    236
    +      let hidden = false;
    
    237
    +      let disabled = false;
    
    238
    +      let active = false;
    
    239
    +      switch (status) {
    
    240
    +        case BreadcrumbStatus.Hidden:
    
    241
    +          hidden = true;
    
    242
    +          break;
    
    243
    +        case BreadcrumbStatus.Disabled:
    
    244
    +          disabled = true;
    
    245
    +          break;
    
    246
    +        case BreadcrumbStatus.Active:
    
    247
    +          active = true;
    
    248
    +          break;
    
    262 249
           }
    
    263
    -      separator?.classList.toggle("hidden", status === BreadcrumbStatus.Hidden);
    
    264
    -    });
    
    250
    +      // NOTE: Hiding or disabling elements can cause them to loose focus.
    
    251
    +      // However, with each stage change the focus should already be moved.
    
    252
    +      listEl.hidden = hidden;
    
    253
    +      const linkEl = listEl.querySelector(".breadcrumb-item");
    
    254
    +      linkEl.classList.toggle("breadcrumb-disabled", disabled);
    
    255
    +      linkEl.classList.toggle("breadcrumb-active", active);
    
    256
    +      if (disabled) {
    
    257
    +        linkEl.removeAttribute("tabindex");
    
    258
    +        linkEl.setAttribute("aria-disabled", "true");
    
    259
    +      } else {
    
    260
    +        linkEl.setAttribute("tabindex", "0");
    
    261
    +        linkEl.removeAttribute("aria-disabled", "true");
    
    262
    +      }
    
    263
    +      if (active) {
    
    264
    +        linkEl.setAttribute("aria-current", "step");
    
    265
    +      } else {
    
    266
    +        linkEl.removeAttribute("aria-current");
    
    267
    +      }
    
    268
    +    }
    
    265 269
       }
    
    266 270
     
    
    267 271
       hideBreadcrumbs() {
    
    268
    -    this.elements.breadcrumbContainer.classList.add("hidden");
    
    272
    +    this.elements.breadcrumbContainer.classList.add("hide-breadcrumbs");
    
    269 273
       }
    
    270 274
     
    
    271 275
       getLocalizedStatus(status) {
    
    ... ... @@ -432,7 +436,11 @@ class AboutTorConnect {
    432 436
             break;
    
    433 437
           case "Bootstrapping":
    
    434 438
             showProgress = true;
    
    435
    -        this.showBootstrapping(stage.bootstrapTrigger, stage.tryAgain);
    
    439
    +        this.showBootstrapping(
    
    440
    +          stage.bootstrapTrigger,
    
    441
    +          stage.tryAgain,
    
    442
    +          stage.potentiallyBlocked
    
    443
    +        );
    
    436 444
             // Always focus the cancel button.
    
    437 445
             moveFocus = this.elements.cancelButton;
    
    438 446
             break;
    
    ... ... @@ -637,10 +645,13 @@ class AboutTorConnect {
    637 645
       }
    
    638 646
     
    
    639 647
       updateBootstrappingStatus(data) {
    
    648
    +    let { progress } = data;
    
    649
    +    progress = Math.max(0, Math.min(progress, 100));
    
    640 650
         this.elements.progressMeter.style.setProperty(
    
    641 651
           "--progress-percent",
    
    642
    -      `${data.progress}%`
    
    652
    +      `${progress}%`
    
    643 653
         );
    
    654
    +    this.elements.progressMeter.setAttribute("aria-valuenow", String(progress));
    
    644 655
         if (this.shownStage === "Bootstrapping" && data.hasWarning) {
    
    645 656
           // When bootstrapping starts, we hide the log button, but we re-show it if
    
    646 657
           // we get a warning.
    
    ... ... @@ -676,16 +687,18 @@ class AboutTorConnect {
    676 687
             BreadcrumbStatus.Default,
    
    677 688
             BreadcrumbStatus.Disabled
    
    678 689
           );
    
    690
    +    } else {
    
    691
    +      this.hideBreadcrumbs();
    
    679 692
         }
    
    680 693
       }
    
    681 694
     
    
    682
    -  showBootstrapping(trigger, tryAgain) {
    
    695
    +  showBootstrapping(trigger, tryAgain, potentiallyBlocked) {
    
    683 696
         let title = "";
    
    684 697
         let description = "";
    
    685 698
         const breadcrumbs = [
    
    686
    -      BreadcrumbStatus.Disabled,
    
    687
    -      BreadcrumbStatus.Disabled,
    
    688
    -      BreadcrumbStatus.Disabled,
    
    699
    +      BreadcrumbStatus.Default,
    
    700
    +      potentiallyBlocked ? BreadcrumbStatus.Default : BreadcrumbStatus.Hidden,
    
    701
    +      potentiallyBlocked ? BreadcrumbStatus.Disabled : BreadcrumbStatus.Hidden,
    
    689 702
         ];
    
    690 703
         switch (trigger) {
    
    691 704
           case "Start":
    
    ... ... @@ -718,7 +731,7 @@ class AboutTorConnect {
    718 731
         this.setTitle(title, "");
    
    719 732
         this.showConfigureConnectionLink(description);
    
    720 733
         this.elements.progressDescription.textContent = "";
    
    721
    -    if (tryAgain) {
    
    734
    +    if (tryAgain || potentiallyBlocked) {
    
    722 735
           this.setBreadcrumbsStatus(...breadcrumbs);
    
    723 736
         } else {
    
    724 737
           this.hideBreadcrumbs();
    
    ... ... @@ -780,8 +793,8 @@ class AboutTorConnect {
    780 793
           this.getMaybeLocalizedError(error);
    
    781 794
         this.setBreadcrumbsStatus(
    
    782 795
           BreadcrumbStatus.Default,
    
    783
    -      BreadcrumbStatus.Default,
    
    784
    -      BreadcrumbStatus.Active
    
    796
    +      BreadcrumbStatus.Active,
    
    797
    +      BreadcrumbStatus.Disabled
    
    785 798
         );
    
    786 799
         this.showLocationForm(false, TorStrings.torConnect.tryAgain);
    
    787 800
       }
    
    ... ... @@ -805,7 +818,8 @@ class AboutTorConnect {
    805 818
         const pieces = text.split("%S");
    
    806 819
         const link = document.createElement("a");
    
    807 820
         link.textContent = TorStrings.torConnect.configureConnection;
    
    808
    -    link.setAttribute("href", "#");
    
    821
    +    link.setAttribute("href", "about:preferences#connection");
    
    822
    +    link.setAttribute("target", "_blank");
    
    809 823
         link.addEventListener("click", e => {
    
    810 824
           e.preventDefault();
    
    811 825
           RPMSendAsyncMessage("torconnect:open-tor-preferences");
    
    ... ... @@ -918,7 +932,7 @@ class AboutTorConnect {
    918 932
         this.populateDelayedRegionOptions();
    
    919 933
     
    
    920 934
         this.show(this.elements.locationDropdownLabel);
    
    921
    -    this.show(this.elements.locationDropdown);
    
    935
    +    this.show(this.elements.locationDropdownSelect);
    
    922 936
         this.elements.locationDropdownLabel.classList.toggle("error", !isChoose);
    
    923 937
         this.show(this.elements.tryBridgeButton, true);
    
    924 938
         if (buttonLabel !== undefined) {
    
    ... ... @@ -929,24 +943,38 @@ class AboutTorConnect {
    929 943
       initElements(direction) {
    
    930 944
         document.documentElement.setAttribute("dir", direction);
    
    931 945
     
    
    932
    -    this.elements.connectToTorLink.addEventListener("click", () => {
    
    933
    -      RPMSendAsyncMessage("torconnect:start-again");
    
    934
    -    });
    
    946
    +    for (const [linkEl, command] of [
    
    947
    +      [
    
    948
    +        this.elements.connectToTorLink,
    
    949
    +        () => {
    
    950
    +          RPMSendAsyncMessage("torconnect:start-again");
    
    951
    +        },
    
    952
    +      ],
    
    953
    +      [
    
    954
    +        this.elements.connectionAssistLink,
    
    955
    +        () => {
    
    956
    +          RPMSendAsyncMessage("torconnect:choose-region");
    
    957
    +        },
    
    958
    +      ],
    
    959
    +      // Final link does nothing.
    
    960
    +    ]) {
    
    961
    +      // NOTE: These link should never be both visible and disabled.
    
    962
    +      // NOTE: We allow re-selecting this link when it is already the
    
    963
    +      // "aria-current" item, to allow the user to reset to the beginning of
    
    964
    +      // Connection Assist.
    
    965
    +      linkEl.addEventListener("click", () => {
    
    966
    +        command();
    
    967
    +      });
    
    968
    +      linkEl.addEventListener("keydown", event => {
    
    969
    +        if (event.key !== "Enter") {
    
    970
    +          return;
    
    971
    +        }
    
    972
    +        command();
    
    973
    +      });
    
    974
    +    }
    
    975
    +
    
    935 976
         this.elements.connectToTorLabel.textContent =
    
    936 977
           TorStrings.torConnect.torConnect;
    
    937
    -    this.elements.connectionAssistLink.addEventListener("click", () => {
    
    938
    -      if (
    
    939
    -        this.elements.connectionAssistLink.classList.contains(
    
    940
    -          BreadcrumbStatus.Active
    
    941
    -        ) ||
    
    942
    -        this.elements.connectionAssistLink.classList.contains(
    
    943
    -          BreadcrumbStatus.Disabled
    
    944
    -        )
    
    945
    -      ) {
    
    946
    -        return;
    
    947
    -      }
    
    948
    -      RPMSendAsyncMessage("torconnect:choose-region");
    
    949
    -    });
    
    950 978
         this.elements.connectionAssistLabel.textContent =
    
    951 979
           TorStrings.torConnect.breadcrumbAssist;
    
    952 980
         this.elements.tryBridgeLabel.textContent =
    
    ... ... @@ -1073,7 +1101,7 @@ class AboutTorConnect {
    1073 1101
         RPMAddMessageListener("torconnect:region-names-change", () => {
    
    1074 1102
           // Reset the regions list.
    
    1075 1103
           this.regions = null;
    
    1076
    -      if (!this.elements.locationDropdown.hidden) {
    
    1104
    +      if (!this.elements.locationDropdownSelect.hidden) {
    
    1077 1105
             // Re-populate immediately.
    
    1078 1106
             this.populateDelayedRegionOptions();
    
    1079 1107
           }
    

  • toolkit/modules/TorConnect.sys.mjs
    ... ... @@ -2,8 +2,6 @@
    2 2
      * License, v. 2.0. If a copy of the MPL was not distributed with this
    
    3 3
      * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
    
    4 4
     
    
    5
    -import { setTimeout, clearTimeout } from "resource://gre/modules/Timer.sys.mjs";
    
    6
    -
    
    7 5
     const lazy = {};
    
    8 6
     
    
    9 7
     ChromeUtils.defineESModuleGetters(lazy, {
    
    ... ... @@ -24,6 +22,10 @@ ChromeUtils.defineESModuleGetters(lazy, {
    24 22
         "moz-src:///toolkit/components/tor-launcher/TorLauncherUtil.sys.mjs",
    
    25 23
       TorSettings: "moz-src:///toolkit/modules/TorSettings.sys.mjs",
    
    26 24
       TorSettingsTopics: "moz-src:///toolkit/modules/TorSettings.sys.mjs",
    
    25
    +  clearInterval: "resource://gre/modules/Timer.sys.mjs",
    
    26
    +  clearTimeout: "resource://gre/modules/Timer.sys.mjs",
    
    27
    +  setInterval: "resource://gre/modules/Timer.sys.mjs",
    
    28
    +  setTimeout: "resource://gre/modules/Timer.sys.mjs",
    
    27 29
     });
    
    28 30
     
    
    29 31
     ChromeUtils.defineLazyGetter(lazy, "NetworkLinkService", () => {
    
    ... ... @@ -122,12 +124,17 @@ export const TorConnectTopics = Object.freeze({
    122 124
      *   bootstrap.
    
    123 125
      * @property {integer} [simulateDelay] - The delay in microseconds to apply to
    
    124 126
      *   simulated bootstraps.
    
    127
    + * @property {number} [simulateProgress] - The progress percent to reach before
    
    128
    + *   the simulated bootstrap fails.
    
    125 129
      * @property {MoatSettings} [simulateMoatResponse] - Simulate a Moat response
    
    126 130
      *   for circumvention settings. Should include a "bridgesList" property, and
    
    127 131
      *   optionally a "country" property. The "bridgesList" property should be an
    
    128 132
      *   Array of MoatBridges objects that match the bridge settings accepted by
    
    129
    - *   TorSettings.bridges, plus you may add a "simulateCensorship" property to
    
    130
    - *   make only their bootstrap attempts fail.
    
    133
    + *   TorSettings.bridges. For each MoatBridges object, you may also add a
    
    134
    + *   "simulateCensorship" property, with an optional "simulateProgress"
    
    135
    + *   property, to make the bootstrap attempt fail for this set of bridges
    
    136
    + *   (whilst still allowing it to pass for other sets of bridges in the
    
    137
    + *   simulated Moat response).
    
    131 138
      * @property {string} [regionCode] - The region code to use to fetch
    
    132 139
      *   auto-bootstrap settings, or "automatic" to automatically choose the region.
    
    133 140
      */
    
    ... ... @@ -232,7 +239,7 @@ class BootstrapAttempt {
    232 239
           this.#bootstrap = {
    
    233 240
             _timeout: 0,
    
    234 241
             bootstrap() {
    
    235
    -          this._timeout = setTimeout(() => {
    
    242
    +          this._timeout = lazy.setTimeout(() => {
    
    236 243
                 const err = new lazy.TorBootstrapError({
    
    237 244
                   summary: "Censorship simulation",
    
    238 245
                   phase: "conn",
    
    ... ... @@ -240,9 +247,32 @@ class BootstrapAttempt {
    240 247
                 });
    
    241 248
                 this.onbootstraperror(err);
    
    242 249
               }, options.simulateDelay || 0);
    
    250
    +          this.onbootstrapstatus(0);
    
    251
    +          if (options.simulateDelay && options.simulateProgress) {
    
    252
    +            let progress = 0;
    
    253
    +            const step = 5;
    
    254
    +            const delay = Math.floor(
    
    255
    +              // We want the last step to last for 10 delay periods to emulate a
    
    256
    +              // short "hang" at this stage.
    
    257
    +              (step * options.simulateDelay) /
    
    258
    +                (options.simulateProgress + 10 * step)
    
    259
    +            );
    
    260
    +            this._progress = lazy.setInterval(() => {
    
    261
    +              progress += step;
    
    262
    +              if (progress >= options.simulateProgress) {
    
    263
    +                progress = options.simulateProgress;
    
    264
    +                lazy.clearInterval(this._progress);
    
    265
    +                delete this._progress;
    
    266
    +              }
    
    267
    +              this.onbootstrapstatus(progress);
    
    268
    +            }, delay);
    
    269
    +          }
    
    243 270
             },
    
    244 271
             cancel() {
    
    245
    -          clearTimeout(this._timeout);
    
    272
    +          lazy.clearTimeout(this._timeout);
    
    273
    +          if (this._progress) {
    
    274
    +            lazy.clearInterval(this._progress);
    
    275
    +          }
    
    246 276
             },
    
    247 277
           };
    
    248 278
         } else {
    
    ... ... @@ -458,6 +488,7 @@ class AutoBootstrapAttempt {
    458 488
                 : TorConnectError.NoSettingsForCountry
    
    459 489
             ),
    
    460 490
           });
    
    491
    +      return;
    
    461 492
         }
    
    462 493
     
    
    463 494
         // Apply each of our settings and try to bootstrap with each.
    
    ... ... @@ -489,7 +520,7 @@ class AutoBootstrapAttempt {
    489 520
       async #fetchBridges(options) {
    
    490 521
         if (options.simulateMoatResponse) {
    
    491 522
           await Promise.race([
    
    492
    -        new Promise(res => setTimeout(res, options.simulateDelay || 0)),
    
    523
    +        new Promise(res => lazy.setTimeout(res, options.simulateDelay || 0)),
    
    493 524
             this.#cancelledPromise,
    
    494 525
           ]);
    
    495 526
     
    
    ... ... @@ -588,8 +619,13 @@ class AutoBootstrapAttempt {
    588 619
           // Move the simulateCensorship option to the options for the next
    
    589 620
           // BootstrapAttempt.
    
    590 621
           bridges = structuredClone(bridges);
    
    622
    +      const simulateProgress = bridges.simulateProgress;
    
    591 623
           delete bridges.simulateCensorship;
    
    624
    +      delete bridges.simulateProgress;
    
    592 625
           options = { ...options, simulateCensorship: true };
    
    626
    +      if (simulateProgress) {
    
    627
    +        options.simulateProgress = simulateProgress;
    
    628
    +      }
    
    593 629
         }
    
    594 630
     
    
    595 631
         // Send the new settings directly to the provider. We will save them only
    
    ... ... @@ -1271,6 +1307,10 @@ export const TorConnect = {
    1271 1307
           bootstrapOptions.simulateDelay =
    
    1272 1308
             this.simulateBootstrapOptions.simulateDelay;
    
    1273 1309
         }
    
    1310
    +    if (this.simulateBootstrapOptions.simulateProgress) {
    
    1311
    +      bootstrapOptions.simulateProgress =
    
    1312
    +        this.simulateBootstrapOptions.simulateProgress;
    
    1313
    +    }
    
    1274 1314
         if (this.simulateBootstrapOptions.simulateMoatResponse) {
    
    1275 1315
           bootstrapOptions.simulateMoatResponse =
    
    1276 1316
             this.simulateBootstrapOptions.simulateMoatResponse;
    
    ... ... @@ -1280,8 +1320,9 @@ export const TorConnect = {
    1280 1320
           TorConnectPrefs.censorship_level,
    
    1281 1321
           0
    
    1282 1322
         );
    
    1283
    -    if (censorshipLevel > 0 && !bootstrapOptions.simulateDelay) {
    
    1284
    -      bootstrapOptions.simulateDelay = 1500;
    
    1323
    +    if (censorshipLevel > 0) {
    
    1324
    +      bootstrapOptions.simulateDelay ||= 1500;
    
    1325
    +      bootstrapOptions.simulateProgress ||= 20;
    
    1285 1326
         }
    
    1286 1327
         if (censorshipLevel === 1) {
    
    1287 1328
           // Bootstrap fails, but auto-bootstrap does not.
    

  • _______________________________________________
    tor-commits mailing list -- tor-commits@xxxxxxxxxxxxxxxxxxxx
    To unsubscribe send an email to tor-commits-leave@xxxxxxxxxxxxxxxxxxxx