lists.torproject.org
Sign In Sign Up
Manage this list Sign In Sign Up

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

tbb-commits

Thread Start a new thread
Download
Threads by month
  • ----- 2025 -----
  • 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
tbb-commits@lists.torproject.org

  • 1 participants
  • 18605 discussions
[tor-browser/tor-browser-80.0b2-10.0-1] Bug 27511: Add new identity button to toolbar
by gk@torproject.org 17 Aug '20

17 Aug '20
commit 23b32cd40e4c91369fd344b0a7c9a7fc190d6ffe Author: Alex Catarineu <acat(a)torproject.org> Date: Fri Oct 4 19:08:33 2019 +0200 Bug 27511: Add new identity button to toolbar Also added 'New circuit for this site' button to CustomizableUI, but not visible by default. --- browser/base/content/browser.xhtml | 10 ++++++++++ .../components/customizableui/CustomizableUI.jsm | 21 +++++++++++++++++++++ browser/themes/shared/icons/new_circuit.svg | 8 ++++++++ browser/themes/shared/icons/new_identity.svg | 9 +++++++++ browser/themes/shared/jar.inc.mn | 3 +++ browser/themes/shared/menupanel.inc.css | 8 ++++++++ browser/themes/shared/toolbarbutton-icons.inc.css | 8 ++++++++ 7 files changed, 67 insertions(+) diff --git a/browser/base/content/browser.xhtml b/browser/base/content/browser.xhtml index 9e115720d0f6..30239396b2eb 100644 --- a/browser/base/content/browser.xhtml +++ b/browser/base/content/browser.xhtml @@ -1893,6 +1893,16 @@ ondragenter="newWindowButtonObserver.onDragOver(event)" ondragexit="newWindowButtonObserver.onDragExit(event)"/> + <toolbarbutton id="new-identity-button" class="toolbarbutton-1 chromeclass-toolbar-additional" + label="&torbutton.context_menu.new_identity;" + oncommand="torbutton_new_identity();" + tooltiptext="&torbutton.context_menu.new_identity;"/> + + <toolbarbutton id="new-circuit-button" class="toolbarbutton-1 chromeclass-toolbar-additional" + label="&torbutton.context_menu.new_circuit;" + oncommand="torbutton_new_circuit();" + tooltiptext="&torbutton.context_menu.new_circuit;"/> + <toolbarbutton id="fullscreen-button" class="toolbarbutton-1 chromeclass-toolbar-additional" observes="View:FullScreen" type="checkbox" diff --git a/browser/components/customizableui/CustomizableUI.jsm b/browser/components/customizableui/CustomizableUI.jsm index 517273b89c53..963667421fc0 100644 --- a/browser/components/customizableui/CustomizableUI.jsm +++ b/browser/components/customizableui/CustomizableUI.jsm @@ -68,6 +68,8 @@ const kSubviewEvents = ["ViewShowing", "ViewHiding"]; */ var kVersion = 16; +var kTorVersion = 1; + /** * Buttons removed from built-ins by version they were removed. kVersion must be * bumped any time a new id is added to this. Use the button id as key, and @@ -566,6 +568,20 @@ var CustomizableUIInternal = { navbarPlacements.push("fxa-toolbar-menu-button"); } } + + let currentTorVersion = gSavedState.currentTorVersion; + if (currentTorVersion < 1 && gSavedState.placements) { + let navbarPlacements = gSavedState.placements[CustomizableUI.AREA_NAVBAR]; + if (navbarPlacements) { + let secLevelIndex = navbarPlacements.indexOf("security-level-button"); + if (secLevelIndex === -1) { + let urlbarIndex = navbarPlacements.indexOf("urlbar-container"); + secLevelIndex = urlbarIndex + 1; + navbarPlacements.splice(secLevelIndex, 0, "security-level-button"); + } + navbarPlacements.splice(secLevelIndex + 1, 0, "new-identity-button"); + } + } }, /** @@ -2354,6 +2370,10 @@ var CustomizableUIInternal = { gSavedState.currentVersion = 0; } + if (!("currentTorVersion" in gSavedState)) { + gSavedState.currentTorVersion = 0; + } + gSeenWidgets = new Set(gSavedState.seen || []); gDirtyAreaCache = new Set(gSavedState.dirtyAreaCache || []); gNewElementCount = gSavedState.newElementCount || 0; @@ -2432,6 +2452,7 @@ var CustomizableUIInternal = { seen: gSeenWidgets, dirtyAreaCache: gDirtyAreaCache, currentVersion: kVersion, + currentTorVersion: kTorVersion, newElementCount: gNewElementCount, }; diff --git a/browser/themes/shared/icons/new_circuit.svg b/browser/themes/shared/icons/new_circuit.svg new file mode 100644 index 000000000000..e0a93cc83502 --- /dev/null +++ b/browser/themes/shared/icons/new_circuit.svg @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <title>Icon / New Circuit(a)1.5x</title> + <g id="Icon-/-New-Circuit" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <path d="M13.4411138,10.1446317 L9.5375349,10.1446317 C8.99786512,10.1446317 8.56164018,10.5818326 8.56164018,11.1205264 C8.56164018,11.6592203 8.99786512,12.0964212 9.5375349,12.0964212 L11.4571198,12.0964212 C10.7554515,13.0479185 9.73466563,13.692009 8.60067597,13.9359827 C8.41818366,13.9720908 8.23276366,14.0033194 8.04734366,14.0218614 C7.97219977,14.0277168 7.89803177,14.0306445 7.82288788,14.0335722 C6.07506044,14.137017 4.290149,13.4499871 3.38647049,11.857327 C2.52280367,10.3349312 2.77263271,8.15966189 3.93687511,6.87343267 C5.12453898,5.56183017 7.44814431,5.04363008 8.21226987,3.38558497 C9.01738301,4.92847451 9.60682342,5.02801577 10.853041,6.15029468 C11.2892659,6.54455615 11.9704404,7.55558307 12.1861132,8.10501179 C12.3051723,8.40949094 12.5013272,9.17947187 12.5013272,9.17947187 L14.2862386,9.17947187 C14.2091429,7.59754654 13.439162,5.96877827 12.2261248,4.93628166 C11.279507,4.13116853 10.5065984,3.84718317 9.77662911,2.8088312 C9.63219669,2.60194152 9.599 99216,2.4565332 9.56290816,2.21646311 C9.53851079,2.00762164 9.54143848,1.78511764 9.62048595,1.53919218 C9.65952174,1.41720534 9.59804037,1.28545955 9.47702943,1.23764071 L6.40296106,0.0167964277 C6.32391359,-0.0134563083 6.23413128,-0.00272146652 6.16679454,0.0480250584 L5.95502539,0.206120002 C5.85743592,0.280288 5.82815908,0.416913259 5.89159223,0.523285783 C6.70060895,1.92564648 6.36978064,2.82542141 5.8984235,3.20211676 C5.4914754,3.4900057 4.99084141,3.72226864 4.63366394,3.95453159 C3.82367132,4.47956294 3.03222071,5.02508808 2.40374451,5.76774396 C0.434388969,8.09427695 0.519291809,12.0046871 2.77165682,14.1077402 C3.65288975,14.9284676 4.70295247,15.4749686 5.81742423,15.7570022 C5.81742423,15.7570022 6.13556591,15.833122 6.21754107,15.8497122 C7.36616915,16.0829511 8.53529102,16.0146384 9.62243774,15.6672199 C9.67416016,15.6525815 9.77174963,15.620377 9.76784605,15.6154975 C10.7730176,15.2700308 11.7049971,14.7010841 12.4652191,13.90573 L12.4652191,15.0241053 C12.4652191, 15.5627992 12.901444,16 13.4411138,16 C13.9798077,16 14.4170085,15.5627992 14.4170085,15.0241053 L14.4170085,11.1205264 C14.4170085,10.5818326 13.9798077,10.1446317 13.4411138,10.1446317" id="Fill-3" fill="context-fill" fill-opacity="context-fill-opacity"></path> + <path d="M5.107,7.462 C4.405,8.078 4,8.946 4,9.839 C4,10.712 4.422,11.57 5.13,12.132 C5.724,12.607 6.627,12.898 7.642,12.949 L7.642,5.8 C7.39,6.029 7.103,6.227 6.791,6.387 C5.993,6.812 5.489,7.133 5.107,7.462" id="Fill-1" fill="context-fill" fill-opacity="context-fill-opacity"></path> + </g> +</svg> diff --git a/browser/themes/shared/icons/new_identity.svg b/browser/themes/shared/icons/new_identity.svg new file mode 100644 index 000000000000..91d5b35f7e80 --- /dev/null +++ b/browser/themes/shared/icons/new_identity.svg @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <title>New Identity Icon</title> + <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <g id="New-Identity-Icon" fill="#000000" fill-rule="nonzero"> + <path d="M4.65687153,14.5532899 L5.79494313,12.0855326 C5.8689125,11.9251399 5.6620883,11.7793527 5.53742729,11.9040137 L3.77194352,13.6694975 L2.32342782,12.2228406 L4.089841,10.4564274 C4.21450201,10.3317664 4.06871482,10.1249422 3.90832206,10.1989116 L1.43773764,11.338287 L0.206601383,10.1087306 C0.0509544211,9.9532834 -0.0167994233,9.75447206 0.00351451705,9.53432844 C0.0238284574,9.31418483 0.154794797,9.13897939 0.330406365,9.0302193 L4.61213917,6.53066101 C4.98542292,6.31331572 5.42541251,6.16259067 5.8659261,6.07796117 C6.63682488,5.92985954 7.40999434,6.06817199 8.09666802,6.42610336 L12.618483,1.910278 C13.0562019,1.47313888 13.7399062,1.45652879 14.1403159,1.87828207 C14.5407256,2.30003536 14.523905,2.96081599 14.0861861,3.39795511 L9.56437119,7.91378047 C9.92258101,8.57753432 10.0391721,9.37155544 9.91292178,10.1416209 C9.85023328,10.5817332 9.67706706,10.9989392 9.45960494,11.3937636 L6.95651989,15.6478297 C6.84761416,15.82321 6.6720026,15.9319701 6.47398108 ,15.9964916 C6.25354962,16.0167745 6.0544801,15.9491049 5.89883314,15.7936577 L4.65687153,14.5532899 L4.65687153,14.5532899 Z M6.35600863,9.57888316 C6.35684236,9.57982492 6.35770616,9.58074275 6.35860024,9.58163642 L7.56801202,10.7899206 C7.78820303,11.010009 8.15567242,10.9533982 8.29166823,10.678253 C8.42766403,10.4031079 8.55818512,10.1511975 8.61427424,9.83946755 C8.73630873,9.14856819 8.51477165,8.45005355 8.01189873,7.92920397 C8.01085853,7.92816425 8.00979562,7.92715687 8.00871022,7.92618158 C8.00773493,7.92509618 8.00672754,7.92403327 8.00568783,7.92299307 C7.48483824,7.42012014 6.7863236,7.19858307 6.09542425,7.32061756 C5.78369428,7.37670668 5.53178393,7.50722777 5.25663877,7.64322357 C4.98149362,7.77921937 4.92488284,8.14668876 5.14497116,8.36687978 L6.35325537,9.57629155 C6.35414904,9.57718564 6.35506687,9.57804944 6.35600863,9.57888316 L6.35600863,9.57888316 Z M3.56503003,4.86094581 C3.44279837,4.85716019 3.33693302,4.76594656 3.31450832,4.6450962 C3.29259157,4.5009814 3 3.24425431,4.36089837 3.1719467,4.23194774 C3.04272848,4.15978087 2.90235166,4.11153221 2.75793184,4.08964745 C2.63678145,4.06729735 2.5453314,3.9616241 2.54155161,3.83961366 C2.53777182,3.71760322 2.62276629,3.61489221 2.74265726,3.59658884 C2.88757581,3.57942626 3.02687427,3.53584537 3.15371096,3.46798665 C3.21938702,3.3436261 3.26061987,3.20700605 3.27529255,3.0651408 C3.29205048,2.94466859 3.39451537,2.85825378 3.5172925,2.86104768 C3.6386065,2.86399065 3.74452528,2.95324633 3.76872081,3.07292141 C3.79288781,3.21715288 3.84342323,3.35694342 3.91777207,3.4852254 C4.04615548,3.55876237 4.18583906,3.60883869 4.32991405,3.63297757 C4.45015386,3.6576218 4.53936117,3.76418021 4.54139495,3.88559216 C4.54342874,4.00700411 4.45770065,4.10814717 4.33816215,4.12536877 C4.1960481,4.14067978 4.05931708,4.18249381 3.9349938,4.24866259 C3.86697751,4.37522253 3.82328954,4.51422019 3.80607564,4.65882867 C3.78847982,4.77811508 3.68677836,4.86339193 3.56503003,4.86094581 Z M14.4103464,14.3126948 C14.2513672,14.307719 14.1137716,14.188804 14.0849193,14.0314492 C14.045996,13.7585014 13.9510862,13.4938971 13.8061961,13.2543814 C13.5663773,13.109665 13.301434,13.0148623 13.0281329,12.9759728 C12.8707684,12.946921 12.75198,12.8095493 12.7470672,12.6509372 C12.7421545,12.492325 12.8525523,12.3587997 13.0082799,12.3350024 C13.2816632,12.3044807 13.5433622,12.2185794 13.7775725,12.0824861 C13.9099238,11.8524988 13.992337,11.5955854 14.0197279,11.3275956 C14.0417134,11.1717293 14.1740126,11.0598594 14.3327736,11.0628895 C14.4905572,11.0667732 14.6282205,11.1831391 14.6593783,11.3389665 C14.703143,11.6110771 14.8017156,11.8740418 14.9490566,12.1117486 C15.1872615,12.2578242 15.450159,12.3559923 15.7221615,12.4004323 C15.8783433,12.4324665 15.9942186,12.5709889 15.9968634,12.7288231 C15.9995083,12.8866572 15.8881575,13.0181443 15.7328877,13.0405352 C15.4641157,13.0669716 15.2064728,13.14931 14.9763475,13.2823129 C14.8406047,13.5164173 14.7548186,13.7777086 14.724105,14.0506041 C14.70 09285,14.2056508 14.5685348,14.3162427 14.4103464,14.3126948 Z M8.37194288,2.75251202 C8.23729358,2.7482977 8.12075529,2.6475812 8.09631849,2.5143077 C8.06335201,2.28313133 7.98296703,2.05902158 7.86025062,1.85616098 C7.65713325,1.73359169 7.43273641,1.65329741 7.2012608,1.62035947 C7.06797908,1.59575373 6.9673698,1.47940513 6.96320889,1.34506671 C6.95904797,1.21072829 7.05255074,1.09763741 7.18444606,1.07748204 C7.41599123,1.0516313 7.6376403,0.978876138 7.83600755,0.863610339 C7.94810399,0.668819911 8.01790485,0.45122403 8.04110388,0.224246882 C8.05972477,0.0922341146 8.17177714,-0.00251545243 8.30624168,5.089704e-05 C8.43987839,0.00334026838 8.55647391,0.101897787 8.58286336,0.233877601 C8.61993042,0.464344927 8.70341768,0.687066016 8.82820981,0.888394549 C9.02996027,1.012115 9.25262444,1.09525963 9.4830002,1.13289867 C9.6152802,1.16003037 9.71342219,1.27735361 9.71566226,1.41103311 C9.71790232,1.5447126 9.62359245,1.65607713 9.49208487,1.67504141 C9.26444525,1.69743199 9.0462315 3,1.76716948 8.85132417,1.87981789 C8.73635526,2.07809534 8.66369764,2.2993991 8.63768445,2.53053117 C8.61805481,2.66184983 8.50592239,2.75551697 8.37194288,2.75251202 Z" id="Shape" fill="context-fill" fill-opacity="context-fill-opacity"></path> + </g> + </g> +</svg> \ No newline at end of file diff --git a/browser/themes/shared/jar.inc.mn b/browser/themes/shared/jar.inc.mn index 36f9ef65a14f..81cfdbcd550b 100644 --- a/browser/themes/shared/jar.inc.mn +++ b/browser/themes/shared/jar.inc.mn @@ -305,3 +305,6 @@ skin/classic/browser/privatebrowsing/private-browsing.svg (../shared/privatebrowsing/private-browsing.svg) skin/classic/browser/install-ssb.svg (../shared/install-ssb.svg) skin/classic/browser/critical.svg (../shared/icons/critical.svg) + + skin/classic/browser/new_circuit.svg (../shared/icons/new_circuit.svg) + skin/classic/browser/new_identity.svg (../shared/icons/new_identity.svg) diff --git a/browser/themes/shared/menupanel.inc.css b/browser/themes/shared/menupanel.inc.css index c919f32a1454..eae453ec5004 100644 --- a/browser/themes/shared/menupanel.inc.css +++ b/browser/themes/shared/menupanel.inc.css @@ -183,3 +183,11 @@ toolbarpaletteitem[place="palette"] > #bookmarks-menu-button, -moz-context-properties: fill, fill-opacity; fill-opacity: 0; } + +#appMenuNewIdentity { + list-style-image: url("chrome://browser/skin/new_identity.svg"); +} + +#appMenuNewCircuit { + list-style-image: url("chrome://browser/skin/new_circuit.svg"); +} diff --git a/browser/themes/shared/toolbarbutton-icons.inc.css b/browser/themes/shared/toolbarbutton-icons.inc.css index ba44da325882..4b4773f0d3a9 100644 --- a/browser/themes/shared/toolbarbutton-icons.inc.css +++ b/browser/themes/shared/toolbarbutton-icons.inc.css @@ -233,6 +233,14 @@ toolbar[brighttext] { list-style-image: url("chrome://browser/skin/new-tab.svg"); } +#new-identity-button { + list-style-image: url("chrome://browser/skin/new_identity.svg"); +} + +#new-circuit-button { + list-style-image: url("chrome://browser/skin/new_circuit.svg"); +} + #privatebrowsing-button { list-style-image: url("chrome://browser/skin/privateBrowsing.svg"); }
1 0
0 0
[tor-browser/tor-browser-80.0b2-10.0-1] Bug 26345: Hide tracking protection UI
by gk@torproject.org 17 Aug '20

17 Aug '20
commit 33c2868a853dcbc4917621d9ea56c4b91fc0518f Author: Alex Catarineu <acat(a)torproject.org> Date: Tue Sep 10 16:29:31 2019 +0200 Bug 26345: Hide tracking protection UI --- browser/base/content/browser-siteIdentity.js | 4 ++-- browser/components/about/AboutRedirector.cpp | 4 ---- browser/components/about/components.conf | 1 - browser/components/customizableui/content/panelUI.inc.xhtml | 4 ++-- browser/components/moz.build | 1 - browser/themes/shared/preferences/privacy.css | 4 ++++ 6 files changed, 8 insertions(+), 10 deletions(-) diff --git a/browser/base/content/browser-siteIdentity.js b/browser/base/content/browser-siteIdentity.js index 46c40e38ce44..54685f828b23 100644 --- a/browser/base/content/browser-siteIdentity.js +++ b/browser/base/content/browser-siteIdentity.js @@ -907,10 +907,10 @@ var gIdentityHandler = { this._refreshPermissionIcons(); - // Hide the shield icon if it is a chrome page. + // Bug 26345: Hide tracking protection UI. gProtectionsHandler._trackingProtectionIconContainer.classList.toggle( "chromeUI", - this._isSecureInternalUI + true ); }, diff --git a/browser/components/about/AboutRedirector.cpp b/browser/components/about/AboutRedirector.cpp index 5021846336aa..78cb284d3eda 100644 --- a/browser/components/about/AboutRedirector.cpp +++ b/browser/components/about/AboutRedirector.cpp @@ -114,10 +114,6 @@ static const RedirEntry kRedirMap[] = { nsIAboutModule::URI_MUST_LOAD_IN_CHILD | nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::HIDE_FROM_ABOUTABOUT}, - {"protections", "chrome://browser/content/protections.html", - nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | - nsIAboutModule::URI_MUST_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT | - nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS}, {"pioneer", "chrome://browser/content/pioneer.html", nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::HIDE_FROM_ABOUTABOUT}, #ifdef TOR_BROWSER_UPDATE diff --git a/browser/components/about/components.conf b/browser/components/about/components.conf index f31159d30e15..d78de142e2e4 100644 --- a/browser/components/about/components.conf +++ b/browser/components/about/components.conf @@ -20,7 +20,6 @@ pages = [ 'policies', 'preferences', 'privatebrowsing', - 'protections', 'profiling', 'reader', 'restartrequired', diff --git a/browser/components/customizableui/content/panelUI.inc.xhtml b/browser/components/customizableui/content/panelUI.inc.xhtml index c84d5dd5c5a3..711c3b7bce5b 100644 --- a/browser/components/customizableui/content/panelUI.inc.xhtml +++ b/browser/components/customizableui/content/panelUI.inc.xhtml @@ -245,7 +245,7 @@ oncommand="gSync.toggleAccountPanel('PanelUI-fxa', this, event)"/> </toolbaritem> <toolbarseparator class="sync-ui-item"/> - <toolbaritem> + <toolbaritem hidden="true"> <toolbarbutton id="appMenu-protection-report-button" class="subviewbutton subviewbutton-iconic" oncommand="gProtectionsHandler.openProtections(); gProtectionsHandler.recordClick('open_full_report', null, 'app_menu');"> @@ -256,7 +256,7 @@ </label> </toolbarbutton> </toolbaritem> - <toolbarseparator id="appMenu-tp-separator"/> + <toolbarseparator hidden="true" id="appMenu-tp-separator"/> <toolbarbutton id="appMenu-new-window-button" class="subviewbutton subviewbutton-iconic" label="&newNavigatorCmd.label;" diff --git a/browser/components/moz.build b/browser/components/moz.build index 8d6d2503e4a0..cb6eeb9164ef 100644 --- a/browser/components/moz.build +++ b/browser/components/moz.build @@ -48,7 +48,6 @@ DIRS += [ 'preferences', 'privatebrowsing', 'prompts', - 'protections', 'protocolhandler', 'resistfingerprinting', 'search', diff --git a/browser/themes/shared/preferences/privacy.css b/browser/themes/shared/preferences/privacy.css index e58d80c5cad9..a6373258d22e 100644 --- a/browser/themes/shared/preferences/privacy.css +++ b/browser/themes/shared/preferences/privacy.css @@ -99,6 +99,10 @@ /* Content Blocking */ +#trackingGroup { + display: none; +} + /* Override styling that sets descriptions as grey */ #trackingGroup description.indent, #trackingGroup .indent > description {
1 0
0 0
[tor-browser/tor-browser-80.0b2-10.0-1] Bug 31563: force reloading search extensions if extensions.enabledScopes has changed
by gk@torproject.org 17 Aug '20

17 Aug '20
commit eb62e6318e064cc38af35d999835020b5189850a Author: Alex Catarineu <acat(a)torproject.org> Date: Sat Aug 31 16:23:20 2019 +0200 Bug 31563: force reloading search extensions if extensions.enabledScopes has changed --- toolkit/components/search/SearchCache.jsm | 8 ++++++++ toolkit/components/search/SearchService.jsm | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/toolkit/components/search/SearchCache.jsm b/toolkit/components/search/SearchCache.jsm index 017c29ee390e..511863bc76e0 100644 --- a/toolkit/components/search/SearchCache.jsm +++ b/toolkit/components/search/SearchCache.jsm @@ -208,6 +208,10 @@ class SearchCache { let locale = Services.locale.requestedLocale; let buildID = Services.appinfo.platformBuildID; let appVersion = Services.appinfo.version; + let enabledScopes = Services.prefs.getIntPref( + "extensions.enabledScopes", + -1 + ); // Allows us to force a cache refresh should the cache format change. cache.version = SearchUtils.CACHE_VERSION; @@ -221,6 +225,10 @@ class SearchCache { cache.appVersion = appVersion; cache.locale = locale; + // Bug 31563: we want to force reloading engines if extensions.enabledScopes + // pref changes + cache.enabledScopes = enabledScopes; + if (gModernConfig) { cache.builtInEngineList = this._searchService._searchOrder; } else { diff --git a/toolkit/components/search/SearchService.jsm b/toolkit/components/search/SearchService.jsm index fa17717d05b7..5fafcabe6ea4 100644 --- a/toolkit/components/search/SearchService.jsm +++ b/toolkit/components/search/SearchService.jsm @@ -1007,7 +1007,9 @@ SearchService.prototype = { !cache.engines || cache.version != SearchUtils.CACHE_VERSION || cache.locale != Services.locale.requestedLocale || - cache.buildID != buildID; + cache.buildID != buildID || + cache.enabledScopes != + Services.prefs.getIntPref("extensions.enabledScopes", -1); let enginesCorrupted = false; if (!rebuildCache) {
1 0
0 0
[tor-browser/tor-browser-80.0b2-10.0-1] Bug 30541: Disable WebGL readPixel() for web content
by gk@torproject.org 17 Aug '20

17 Aug '20
commit efd81bac2d4a03c613dbb5cf076a63873ee4f0d9 Author: Georg Koppen <gk(a)torproject.org> Date: Wed May 29 12:29:19 2019 +0000 Bug 30541: Disable WebGL readPixel() for web content --- dom/canvas/ClientWebGLContext.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dom/canvas/ClientWebGLContext.cpp b/dom/canvas/ClientWebGLContext.cpp index 3107da6cc779..d4bbb5208395 100644 --- a/dom/canvas/ClientWebGLContext.cpp +++ b/dom/canvas/ClientWebGLContext.cpp @@ -4532,6 +4532,14 @@ bool ClientWebGLContext::ReadPixels_SharedPrecheck( return false; } + // Security check passed, but don't let content readPixel calls through for + // now, if Resist Fingerprinting Mode is enabled. + if (nsContentUtils::ResistFingerprinting(aCallerType)) { + JsWarning("readPixels: Not allowed in Resist Fingerprinting Mode"); + out_error.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return false; + } + return true; }
1 0
0 0
[tor-browser/tor-browser-80.0b2-10.0-1] Bug 32092: Fix Tor Browser Support link in preferences
by gk@torproject.org 17 Aug '20

17 Aug '20
commit fc8457b5fcd25d7cb162d9bcfe76f0e603464755 Author: Alex Catarineu <acat(a)torproject.org> Date: Tue Oct 15 22:54:10 2019 +0200 Bug 32092: Fix Tor Browser Support link in preferences --- browser/components/preferences/preferences.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/browser/components/preferences/preferences.js b/browser/components/preferences/preferences.js index fcb722eea0b2..9e97ca2a2180 100644 --- a/browser/components/preferences/preferences.js +++ b/browser/components/preferences/preferences.js @@ -166,10 +166,7 @@ function init_all() { gotoPref().then(() => { let helpButton = document.getElementById("helpButton"); - let helpUrl = - Services.urlFormatter.formatURLPref("app.support.baseURL") + - "preferences"; - helpButton.setAttribute("href", helpUrl); + helpButton.setAttribute("href", "https://support.torproject.org/tbb"); document.getElementById("addonsButton").addEventListener("click", e => { if (e.button >= 2) {
1 0
0 0
[tor-browser/tor-browser-80.0b2-10.0-1] Bug 13543: Spoof smooth and powerEfficient for Media Capabilities
by gk@torproject.org 17 Aug '20

17 Aug '20
commit a23fa11927fe9dc7e8bbda7611281196d5cb6a40 Author: Alex Catarineu <acat(a)torproject.org> Date: Thu Oct 10 15:08:12 2019 +0200 Bug 13543: Spoof smooth and powerEfficient for Media Capabilities --- dom/media/mediacapabilities/MediaCapabilities.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dom/media/mediacapabilities/MediaCapabilities.cpp b/dom/media/mediacapabilities/MediaCapabilities.cpp index 3f3f6285ee2b..a0360cff1b91 100644 --- a/dom/media/mediacapabilities/MediaCapabilities.cpp +++ b/dom/media/mediacapabilities/MediaCapabilities.cpp @@ -288,6 +288,11 @@ already_AddRefed<Promise> MediaCapabilities::DecodingInfo( if (aValue.IsReject()) { p = CapabilitiesPromise::CreateAndReject( std::move(aValue.RejectValue()), __func__); + } else if (nsContentUtils:: + ShouldResistFingerprinting()) { + p = CapabilitiesPromise::CreateAndResolve( + MediaCapabilitiesInfo(true, true, false), + __func__); } else { MOZ_ASSERT(config->IsVideo()); if (StaticPrefs::media_mediacapabilities_from_database()) {
1 0
0 0
[tor-browser/tor-browser-80.0b2-10.0-1] Bug 32220: Improve the letterboxing experience
by gk@torproject.org 17 Aug '20

17 Aug '20
commit 8b3716012e3a12c0465442280dc4324055d0ae3e Author: Richard Pospesel <richard(a)torproject.org> Date: Mon Oct 28 17:42:17 2019 -0700 Bug 32220: Improve the letterboxing experience CSS and JS changes to alter the UX surrounding letterboxing. The browser element containing page content is now anchored to the bottom of the toolbar, and the remaining letterbox margin is the same color as the firefox chrome. The letterbox margin and border are tied to the currently selected theme. Also adds a 'needsLetterbox' property to tabbrowser.xml to fix a race condition present when using the 'isEmpty' property. Using 'isEmpty' as a proxy for 'needsLetterbox' resulted in over-zealous/unnecessary letterboxing of about:blank tabs. --- browser/base/content/browser.css | 8 ++ browser/base/content/tabbrowser-tab.js | 9 +++ browser/themes/shared/tabs.inc.css | 6 ++ .../components/resistfingerprinting/RFPHelper.jsm | 94 +++++++++++++++++++--- 4 files changed, 105 insertions(+), 12 deletions(-) diff --git a/browser/base/content/browser.css b/browser/base/content/browser.css index 5a00107d8f88..23a695645a77 100644 --- a/browser/base/content/browser.css +++ b/browser/base/content/browser.css @@ -85,6 +85,14 @@ body { display: none; } + +.browserStack > browser.letterboxing { + border-color: var(--chrome-content-separator-color); + border-style: solid; + border-width : 1px; + border-top: none; +} + %ifdef MENUBAR_CAN_AUTOHIDE #toolbar-menubar[autohide="true"] { overflow: hidden; diff --git a/browser/base/content/tabbrowser-tab.js b/browser/base/content/tabbrowser-tab.js index 183eff1bab86..7f376ab1d122 100644 --- a/browser/base/content/tabbrowser-tab.js +++ b/browser/base/content/tabbrowser-tab.js @@ -225,6 +225,15 @@ return true; } + get needsLetterbox() { + let browser = this.linkedBrowser; + if (isBlankPageURL(browser.currentURI.spec)) { + return false; + } + + return true; + } + get lastAccessed() { return this._lastAccessed == Infinity ? Date.now() : this._lastAccessed; } diff --git a/browser/themes/shared/tabs.inc.css b/browser/themes/shared/tabs.inc.css index b8a117532049..cf8f444b262d 100644 --- a/browser/themes/shared/tabs.inc.css +++ b/browser/themes/shared/tabs.inc.css @@ -33,6 +33,12 @@ background-color: #f9f9fa; } +/* extend down the toolbar's colors when letterboxing is enabled*/ +#tabbrowser-tabpanels.letterboxing { + background-color: var(--toolbar-bgcolor); + background-image: var(--toolbar-bgimage); +} + :root[privatebrowsingmode=temporary] #tabbrowser-tabpanels { /* Value for --in-content-page-background in aboutPrivateBrowsing.css */ background-color: #25003e; diff --git a/toolkit/components/resistfingerprinting/RFPHelper.jsm b/toolkit/components/resistfingerprinting/RFPHelper.jsm index 166ad21e9013..9520d8720631 100644 --- a/toolkit/components/resistfingerprinting/RFPHelper.jsm +++ b/toolkit/components/resistfingerprinting/RFPHelper.jsm @@ -40,6 +40,7 @@ class _RFPHelper { // ============================================================================ constructor() { this._initialized = false; + this._borderDimensions = null; } init() { @@ -361,6 +362,24 @@ class _RFPHelper { }); } + getBorderDimensions(aBrowser) { + if (this._borderDimensions) { + return this._borderDimensions; + } + + const win = aBrowser.ownerGlobal; + const browserStyle = win.getComputedStyle(aBrowser); + + this._borderDimensions = { + top : parseInt(browserStyle.borderTopWidth), + right: parseInt(browserStyle.borderRightWidth), + bottom : parseInt(browserStyle.borderBottomWidth), + left : parseInt(browserStyle.borderLeftWidth), + }; + + return this._borderDimensions; + } + _addOrClearContentMargin(aBrowser) { let tab = aBrowser.getTabBrowser().getTabForBrowser(aBrowser); @@ -369,9 +388,13 @@ class _RFPHelper { return; } + // we add the letterboxing class even if the content does not need letterboxing + // in which case margins are set such that the borders are hidden + aBrowser.classList.add("letterboxing"); + // We should apply no margin around an empty tab or a tab with system // principal. - if (tab.isEmpty || aBrowser.contentPrincipal.isSystemPrincipal) { + if (!tab.needsLetterbox || aBrowser.contentPrincipal.isSystemPrincipal) { this._clearContentViewMargin(aBrowser); } else { this._roundContentView(aBrowser); @@ -539,10 +562,29 @@ class _RFPHelper { // Calculating the margins around the browser element in order to round the // content viewport. We will use a 200x100 stepping if the dimension set // is not given. - let margins = calcMargins(containerWidth, containerHeight); + + const borderDimensions = this.getBorderDimensions(aBrowser); + const marginDims = calcMargins(containerWidth, containerHeight - borderDimensions.top); + + let margins = { + top : 0, + right : 0, + bottom : 0, + left : 0, + }; + + // snap browser element to top + margins.top = 0; + // and leave 'double' margin at the bottom + margins.bottom = 2 * marginDims.height - borderDimensions.bottom; + // identical margins left and right + margins.right = marginDims.width - borderDimensions.right; + margins.left = marginDims.width - borderDimensions.left; + + const marginStyleString = `${margins.top}px ${margins.right}px ${margins.bottom}px ${margins.left}px`; // If the size of the content is already quantized, we do nothing. - if (aBrowser.style.margin == `${margins.height}px ${margins.width}px`) { + if (aBrowser.style.margin === marginStyleString) { log("_roundContentView[" + logId + "] is_rounded == true"); if (this._isLetterboxingTesting) { log( @@ -563,19 +605,35 @@ class _RFPHelper { "_roundContentView[" + logId + "] setting margins to " + - margins.width + - " x " + - margins.height + marginStyleString ); - // One cannot (easily) control the color of a margin unfortunately. - // An initial attempt to use a border instead of a margin resulted - // in offset event dispatching; so for now we use a colorless margin. - aBrowser.style.margin = `${margins.height}px ${margins.width}px`; + + // The margin background color is determined by the background color of the + // window's tabpanels#tabbrowser-tabpanels element + aBrowser.style.margin = marginStyleString; }); } _clearContentViewMargin(aBrowser) { + const borderDimensions = this.getBorderDimensions(aBrowser); + // set the margins such that the browser elements border is visible up top, but + // are rendered off-screen on the remaining sides + let margins = { + top : 0, + right : -borderDimensions.right, + bottom : -borderDimensions.bottom, + left : -borderDimensions.left, + }; + const marginStyleString = `${margins.top}px ${margins.right}px ${margins.bottom}px ${margins.left}px`; + + aBrowser.ownerGlobal.requestAnimationFrame(() => { + aBrowser.style.margin = marginStyleString; + }); + } + + _removeLetterboxing(aBrowser) { aBrowser.ownerGlobal.requestAnimationFrame(() => { + aBrowser.classList.remove("letterboxing"); aBrowser.style.margin = ""; }); } @@ -593,6 +651,11 @@ class _RFPHelper { aWindow.gBrowser.addTabsProgressListener(this); aWindow.addEventListener("TabOpen", this); + const tabPanel = aWindow.document.getElementById("tabbrowser-tabpanels"); + if (tabPanel) { + tabPanel.classList.add("letterboxing"); + } + // Rounding the content viewport. this._updateMarginsForTabsInWindow(aWindow); } @@ -616,10 +679,17 @@ class _RFPHelper { tabBrowser.removeTabsProgressListener(this); aWindow.removeEventListener("TabOpen", this); - // Clear all margins and tooltip for all browsers. + // revert tabpanel's background colors to default + const tabPanel = aWindow.document.getElementById("tabbrowser-tabpanels"); + if (tabPanel) { + tabPanel.classList.remove("letterboxing"); + } + + // and revert each browser element to default, + // restore default margins and remove letterboxing class for (let tab of tabBrowser.tabs) { let browser = tab.linkedBrowser; - this._clearContentViewMargin(browser); + this._removeLetterboxing(browser); } }
1 0
0 0
[tor-browser/tor-browser-80.0b2-10.0-1] Bug 31740: Remove some unnecessary RemoteSettings instances
by gk@torproject.org 17 Aug '20

17 Aug '20
commit 6f4d7b194ad3e2b4edc23682db590242deff028c Author: Alex Catarineu <acat(a)torproject.org> Date: Wed Oct 16 23:01:12 2019 +0200 Bug 31740: Remove some unnecessary RemoteSettings instances More concretely, SearchService.jsm 'hijack-blocklists' and url-classifier-skip-urls. --- netwerk/url-classifier/UrlClassifierFeatureBase.cpp | 2 +- netwerk/url-classifier/components.conf | 6 ------ toolkit/components/search/SearchService.jsm | 2 -- 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/netwerk/url-classifier/UrlClassifierFeatureBase.cpp b/netwerk/url-classifier/UrlClassifierFeatureBase.cpp index 07da1fd07374..48bcc7d10af9 100644 --- a/netwerk/url-classifier/UrlClassifierFeatureBase.cpp +++ b/netwerk/url-classifier/UrlClassifierFeatureBase.cpp @@ -78,7 +78,7 @@ void UrlClassifierFeatureBase::InitializePreferences() { nsCOMPtr<nsIUrlClassifierExceptionListService> exceptionListService = do_GetService("@mozilla.org/url-classifier/exception-list-service;1"); - if (NS_WARN_IF(!exceptionListService)) { + if (!exceptionListService) { return; } diff --git a/netwerk/url-classifier/components.conf b/netwerk/url-classifier/components.conf index 03a02f0ebeab..b2e667247317 100644 --- a/netwerk/url-classifier/components.conf +++ b/netwerk/url-classifier/components.conf @@ -13,10 +13,4 @@ Classes = [ 'constructor': 'mozilla::net::ChannelClassifierService::GetSingleton', 'headers': ['mozilla/net/ChannelClassifierService.h'], }, - { - 'cid': '{b9f4fd03-9d87-4bfd-9958-85a821750ddc}', - 'contract_ids': ['@mozilla.org/url-classifier/exception-list-service;1'], - 'jsm': 'resource://gre/modules/UrlClassifierExceptionListService.jsm', - 'constructor': 'UrlClassifierExceptionListService', - }, ] diff --git a/toolkit/components/search/SearchService.jsm b/toolkit/components/search/SearchService.jsm index 5fafcabe6ea4..1e97c871efa0 100644 --- a/toolkit/components/search/SearchService.jsm +++ b/toolkit/components/search/SearchService.jsm @@ -539,8 +539,6 @@ SearchService.prototype = { .catch(ex => logConsole.error("_init: failure determining region:", ex)) .finally(() => (this._ensureKnownRegionPromise = null)); - this._setupRemoteSettings().catch(Cu.reportError); - await this._loadEngines(cache); // If we've got this far, but the application is now shutting down,
1 0
0 0
[tor-browser/tor-browser-80.0b2-10.0-1] Bug 30237: Add v3 onion services client authentication prompt
by gk@torproject.org 17 Aug '20

17 Aug '20
commit 96cbd3468d395c8565d8a330bbd90e49e5d096b3 Author: Kathy Brade <brade(a)pearlcrescent.com> Date: Tue Nov 12 16:11:05 2019 -0500 Bug 30237: Add v3 onion services client authentication prompt When Tor informs the browser that client authentication is needed, temporarily load about:blank instead of about:neterror and prompt for the user's key. If a correctly formatted key is entered, use Tor's ONION_CLIENT_AUTH_ADD control port command to add the key (via Torbutton's control port module) and reload the page. If the user cancels the prompt, display the standard about:neterror "Unable to connect" page. This requires a small change to browser/actors/NetErrorChild.jsm to account for the fact that the docShell no longer has the failedChannel information. The failedChannel is used to extract TLS-related error info, which is not applicable in the case of a canceled .onion authentication prompt. Add a leaveOpen option to PopupNotifications.show so we can display error messages within the popup notification doorhanger without closing the prompt. Add support for onion services strings to the TorStrings module. Add support for Tor extended SOCKS errors (Tor proposal 304) to the socket transport and SOCKS layers. Improved display of all of these errors will be implemented as part of bug 30025. Also fixes bug 19757: Add a "Remember this key" checkbox to the client auth prompt. Add an "Onion Services Authentication" section within the about:preferences "Privacy & Security section" to allow viewing and removal of v3 onion client auth keys that have been stored on disk. Also fixes bug 19251: use enhanced error pages for onion service errors. --- browser/actors/NetErrorChild.jsm | 7 + browser/base/content/aboutNetError.js | 10 +- browser/base/content/aboutNetError.xhtml | 1 + browser/base/content/browser.js | 10 + browser/base/content/browser.xhtml | 3 + browser/base/content/tab-content.js | 5 + browser/components/moz.build | 1 + .../content/authNotificationIcon.inc.xhtml | 6 + .../onionservices/content/authPopup.inc.xhtml | 16 ++ .../onionservices/content/authPreferences.css | 20 ++ .../content/authPreferences.inc.xhtml | 19 ++ .../onionservices/content/authPreferences.js | 66 +++++ .../components/onionservices/content/authPrompt.js | 316 +++++++++++++++++++++ .../components/onionservices/content/authUtil.jsm | 47 +++ .../onionservices/content/netError/browser.svg | 3 + .../onionservices/content/netError/network.svg | 3 + .../content/netError/onionNetError.css | 65 +++++ .../content/netError/onionNetError.js | 244 ++++++++++++++++ .../onionservices/content/netError/onionsite.svg | 7 + .../onionservices/content/onionservices.css | 69 +++++ .../onionservices/content/savedKeysDialog.js | 259 +++++++++++++++++ .../onionservices/content/savedKeysDialog.xhtml | 42 +++ browser/components/onionservices/jar.mn | 9 + browser/components/onionservices/moz.build | 1 + browser/components/preferences/preferences.xhtml | 1 + browser/components/preferences/privacy.inc.xhtml | 2 + browser/components/preferences/privacy.js | 7 + browser/themes/shared/notification-icons.inc.css | 3 + docshell/base/nsDocShell.cpp | 81 +++++- dom/ipc/BrowserParent.cpp | 21 ++ dom/ipc/BrowserParent.h | 3 + dom/ipc/PBrowser.ipdl | 9 + js/xpconnect/src/xpc.msg | 10 + netwerk/base/nsSocketTransport2.cpp | 6 + netwerk/socket/nsSOCKSIOLayer.cpp | 49 ++++ toolkit/modules/PopupNotifications.jsm | 6 + toolkit/modules/RemotePageAccessManager.jsm | 1 + .../lib/environments/frame-script.js | 1 + xpcom/base/ErrorList.py | 22 ++ 39 files changed, 1449 insertions(+), 2 deletions(-) diff --git a/browser/actors/NetErrorChild.jsm b/browser/actors/NetErrorChild.jsm index eea7ddd0cf97..58bab60c36f7 100644 --- a/browser/actors/NetErrorChild.jsm +++ b/browser/actors/NetErrorChild.jsm @@ -13,6 +13,8 @@ const { RemotePageChild } = ChromeUtils.import( "resource://gre/actors/RemotePageChild.jsm" ); +const { TorStrings } = ChromeUtils.import("resource:///modules/TorStrings.jsm"); + XPCOMUtils.defineLazyServiceGetter( this, "gSerializationHelper", @@ -30,6 +32,7 @@ class NetErrorChild extends RemotePageChild { "RPMAddToHistogram", "RPMRecordTelemetryEvent", "RPMGetHttpResponseHeader", + "RPMGetTorStrings", ]; this.exportFunctions(exportableFunctions); } @@ -103,4 +106,8 @@ class NetErrorChild extends RemotePageChild { return ""; } + + RPMGetTorStrings() { + return Cu.cloneInto(TorStrings.onionServices, this.contentWindow); + } } diff --git a/browser/base/content/aboutNetError.js b/browser/base/content/aboutNetError.js index fd12295b05fd..4e40e53da199 100644 --- a/browser/base/content/aboutNetError.js +++ b/browser/base/content/aboutNetError.js @@ -3,6 +3,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ /* eslint-env mozilla/frame-script */ +/* import-globals-from ../../components/onionservices/content/netError/onionNetError.js */ const formatter = new Intl.DateTimeFormat("default"); @@ -280,7 +281,10 @@ function initPage() { errDesc = document.getElementById("ed_generic"); } - setErrorPageStrings(err); + const isOnionError = err.startsWith("onionServices."); + if (!isOnionError) { + setErrorPageStrings(err); + } var sd = document.getElementById("errorShortDescText"); if (sd) { @@ -433,6 +437,10 @@ function initPage() { span.textContent = document.location.hostname; } } + + if (isOnionError) { + OnionServicesAboutNetError.initPage(document); + } } function setupErrorUI() { diff --git a/browser/base/content/aboutNetError.xhtml b/browser/base/content/aboutNetError.xhtml index 75c95cc17011..4f21e508be0b 100644 --- a/browser/base/content/aboutNetError.xhtml +++ b/browser/base/content/aboutNetError.xhtml @@ -215,6 +215,7 @@ </div> </div> </body> + <script src="chrome://browser/content/onionservices/netError/onionNetError.js"/> <script src="chrome://browser/content/aboutNetErrorCodes.js"/> <script src="chrome://browser/content/aboutNetError.js"/> </html> diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index fdbce2d6acde..7b1ad4773ab6 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -220,6 +220,11 @@ XPCOMUtils.defineLazyScriptGetter( ["SecurityLevelButton"], "chrome://browser/content/securitylevel/securityLevel.js" ); +XPCOMUtils.defineLazyScriptGetter( + this, + ["OnionAuthPrompt"], + "chrome://browser/content/onionservices/authPrompt.js" +); XPCOMUtils.defineLazyScriptGetter( this, "gEditItemOverlay", @@ -1859,6 +1864,9 @@ var gBrowserInit = { // Init the SecuritySettingsButton SecurityLevelButton.init(); + // Init the OnionAuthPrompt + OnionAuthPrompt.init(); + // Certain kinds of automigration rely on this notification to complete // their tasks BEFORE the browser window is shown. SessionStore uses it to // restore tabs into windows AFTER important parts like gMultiProcessBrowser @@ -2464,6 +2472,8 @@ var gBrowserInit = { SecurityLevelButton.uninit(); + OnionAuthPrompt.uninit(); + gAccessibilityServiceIndicator.uninit(); AccessibilityRefreshBlocker.uninit(); diff --git a/browser/base/content/browser.xhtml b/browser/base/content/browser.xhtml index 30239396b2eb..07b84e5e4473 100644 --- a/browser/base/content/browser.xhtml +++ b/browser/base/content/browser.xhtml @@ -33,6 +33,7 @@ <?xml-stylesheet href="chrome://browser/skin/places/editBookmark.css" type="text/css"?> <?xml-stylesheet href="chrome://torbutton/skin/tor-circuit-display.css" type="text/css"?> <?xml-stylesheet href="chrome://torbutton/skin/torbutton.css" type="text/css"?> +<?xml-stylesheet href="chrome://browser/content/onionservices/onionservices.css" type="text/css"?> # All DTD information is stored in a separate file so that it can be shared by # hiddenWindowMac.xhtml. @@ -631,6 +632,7 @@ #include ../../components/downloads/content/downloadsPanel.inc.xhtml #include ../../../devtools/startup/enableDevToolsPopup.inc.xhtml #include ../../components/securitylevel/content/securityLevelPanel.inc.xhtml +#include ../../components/onionservices/content/authPopup.inc.xhtml #include browser-allTabsMenu.inc.xhtml <hbox id="downloads-animation-container"> @@ -1586,6 +1588,7 @@ data-l10n-id="urlbar-indexed-db-notification-anchor"/> <image id="password-notification-icon" class="notification-anchor-icon login-icon" role="button" data-l10n-id="urlbar-password-notification-anchor"/> +#include ../../components/onionservices/content/authNotificationIcon.inc.xhtml <stack id="plugins-notification-icon" class="notification-anchor-icon" role="button" align="center" data-l10n-id="urlbar-plugins-notification-anchor"> <image class="plugin-icon" /> <image id="plugin-icon-badge" /> diff --git a/browser/base/content/tab-content.js b/browser/base/content/tab-content.js index 1a01d4a2ded9..79fd7f39243d 100644 --- a/browser/base/content/tab-content.js +++ b/browser/base/content/tab-content.js @@ -19,6 +19,9 @@ ChromeUtils.defineModuleGetter( "BrowserUtils", "resource://gre/modules/BrowserUtils.jsm" ); +var { OnionAuthUtil } = ChromeUtils.import( + "chrome://browser/content/onionservices/authUtil.jsm" +); // BrowserChildGlobal var global = this; @@ -73,5 +76,7 @@ if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) { Services.obs.notifyObservers(this, "tab-content-frameloader-created"); +OnionAuthUtil.addCancelMessageListener(this, docShell); + // This is a temporary hack to prevent regressions (bug 1471327). void content; diff --git a/browser/components/moz.build b/browser/components/moz.build index 09e209dc9c3b..b660be047b14 100644 --- a/browser/components/moz.build +++ b/browser/components/moz.build @@ -41,6 +41,7 @@ DIRS += [ 'fxmonitor', 'migration', 'newtab', + 'onionservices', 'originattributes', 'pioneer', 'places', diff --git a/browser/components/onionservices/content/authNotificationIcon.inc.xhtml b/browser/components/onionservices/content/authNotificationIcon.inc.xhtml new file mode 100644 index 000000000000..91274d612739 --- /dev/null +++ b/browser/components/onionservices/content/authNotificationIcon.inc.xhtml @@ -0,0 +1,6 @@ +# Copyright (c) 2020, The Tor Project, Inc. + +<image id="tor-clientauth-notification-icon" + class="notification-anchor-icon tor-clientauth-icon" + role="button" + tooltiptext="&torbutton.onionServices.authPrompt.tooltip;"/> diff --git a/browser/components/onionservices/content/authPopup.inc.xhtml b/browser/components/onionservices/content/authPopup.inc.xhtml new file mode 100644 index 000000000000..bd0ec3aa0b00 --- /dev/null +++ b/browser/components/onionservices/content/authPopup.inc.xhtml @@ -0,0 +1,16 @@ +# Copyright (c) 2020, The Tor Project, Inc. + +<popupnotification id="tor-clientauth-notification" hidden="true"> + <popupnotificationcontent orient="vertical"> + <description id="tor-clientauth-notification-desc"/> + <label id="tor-clientauth-notification-learnmore" + class="text-link popup-notification-learnmore-link" + is="text-link"/> + <html:div> + <html:input id="tor-clientauth-notification-key" type="password"/> + <html:div id="tor-clientauth-warning"/> + <checkbox id="tor-clientauth-persistkey-checkbox" + label="&torbutton.onionServices.authPrompt.persistCheckboxLabel;"/> + </html:div> + </popupnotificationcontent> +</popupnotification> diff --git a/browser/components/onionservices/content/authPreferences.css b/browser/components/onionservices/content/authPreferences.css new file mode 100644 index 000000000000..b3fb79b26ddc --- /dev/null +++ b/browser/components/onionservices/content/authPreferences.css @@ -0,0 +1,20 @@ +/* Copyright (c) 2020, The Tor Project, Inc. */ + +#torOnionServiceKeys-overview-container { + margin-right: 30px; +} + +#onionservices-savedkeys-tree treechildren::-moz-tree-cell-text { + font-size: 80%; +} + +#onionservices-savedkeys-errorContainer { + margin-top: 4px; + min-height: 3em; +} + +#onionservices-savedkeys-errorIcon { + margin-right: 4px; + list-style-image: url("chrome://browser/skin/warning.svg"); + visibility: hidden; +} diff --git a/browser/components/onionservices/content/authPreferences.inc.xhtml b/browser/components/onionservices/content/authPreferences.inc.xhtml new file mode 100644 index 000000000000..f69c9dde66a2 --- /dev/null +++ b/browser/components/onionservices/content/authPreferences.inc.xhtml @@ -0,0 +1,19 @@ +# Copyright (c) 2020, The Tor Project, Inc. + +<groupbox id="torOnionServiceKeys" orient="vertical" + data-category="panePrivacy" hidden="true"> + <label><html:h2 id="torOnionServiceKeys-header"/></label> + <hbox> + <description id="torOnionServiceKeys-overview-container" flex="1"> + <html:span id="torOnionServiceKeys-overview" + class="tail-with-learn-more"/> + <label id="torOnionServiceKeys-learnMore" class="learnMore text-link" + is="text-link"/> + </description> + <vbox align="end"> + <button id="torOnionServiceKeys-savedKeys" + is="highlightable-button" + class="accessory-button"/> + </vbox> + </hbox> +</groupbox> diff --git a/browser/components/onionservices/content/authPreferences.js b/browser/components/onionservices/content/authPreferences.js new file mode 100644 index 000000000000..52f8272020cc --- /dev/null +++ b/browser/components/onionservices/content/authPreferences.js @@ -0,0 +1,66 @@ +// Copyright (c) 2020, The Tor Project, Inc. + +"use strict"; + +ChromeUtils.defineModuleGetter( + this, + "TorStrings", + "resource:///modules/TorStrings.jsm" +); + +/* + Onion Services Client Authentication Preferences Code + + Code to handle init and update of onion services authentication section + in about:preferences#privacy +*/ + +const OnionServicesAuthPreferences = { + selector: { + groupBox: "#torOnionServiceKeys", + header: "#torOnionServiceKeys-header", + overview: "#torOnionServiceKeys-overview", + learnMore: "#torOnionServiceKeys-learnMore", + savedKeysButton: "#torOnionServiceKeys-savedKeys", + }, + + init() { + // populate XUL with localized strings + this._populateXUL(); + }, + + _populateXUL() { + const groupbox = document.querySelector(this.selector.groupBox); + + let elem = groupbox.querySelector(this.selector.header); + elem.textContent = TorStrings.onionServices.authPreferences.header; + + elem = groupbox.querySelector(this.selector.overview); + elem.textContent = TorStrings.onionServices.authPreferences.overview; + + elem = groupbox.querySelector(this.selector.learnMore); + elem.setAttribute("value", TorStrings.onionServices.learnMore); + elem.setAttribute("href", TorStrings.onionServices.learnMoreURL); + + elem = groupbox.querySelector(this.selector.savedKeysButton); + elem.setAttribute( + "label", + TorStrings.onionServices.authPreferences.savedKeys + ); + elem.addEventListener("command", () => + OnionServicesAuthPreferences.onViewSavedKeys() + ); + }, + + onViewSavedKeys() { + gSubDialog.open( + "chrome://browser/content/onionservices/savedKeysDialog.xhtml" + ); + }, +}; // OnionServicesAuthPreferences + +Object.defineProperty(this, "OnionServicesAuthPreferences", { + value: OnionServicesAuthPreferences, + enumerable: true, + writable: false, +}); diff --git a/browser/components/onionservices/content/authPrompt.js b/browser/components/onionservices/content/authPrompt.js new file mode 100644 index 000000000000..d4a59ac46487 --- /dev/null +++ b/browser/components/onionservices/content/authPrompt.js @@ -0,0 +1,316 @@ +// Copyright (c) 2020, The Tor Project, Inc. + +"use strict"; + +XPCOMUtils.defineLazyModuleGetters(this, { + OnionAuthUtil: "chrome://browser/content/onionservices/authUtil.jsm", + CommonUtils: "resource://services-common/utils.js", + TorStrings: "resource:///modules/TorStrings.jsm", +}); + +const OnionAuthPrompt = (function() { + // OnionServicesAuthPrompt objects run within the main/chrome process. + // aReason is the topic passed within the observer notification that is + // causing this auth prompt to be displayed. + function OnionServicesAuthPrompt(aBrowser, aFailedURI, aReason, aOnionName) { + this._browser = aBrowser; + this._failedURI = aFailedURI; + this._reasonForPrompt = aReason; + this._onionName = aOnionName; + } + + OnionServicesAuthPrompt.prototype = { + show(aWarningMessage) { + let mainAction = { + label: TorStrings.onionServices.authPrompt.done, + accessKey: TorStrings.onionServices.authPrompt.doneAccessKey, + leaveOpen: true, // Callback is responsible for closing the notification. + callback: this._onDone.bind(this), + }; + + let dialogBundle = Services.strings.createBundle( + "chrome://global/locale/dialog.properties"); + + let cancelAccessKey = dialogBundle.GetStringFromName("accesskey-cancel"); + if (!cancelAccessKey) + cancelAccessKey = "c"; // required by PopupNotifications.show() + + let cancelAction = { + label: dialogBundle.GetStringFromName("button-cancel"), + accessKey: cancelAccessKey, + callback: this._onCancel.bind(this), + }; + + let _this = this; + let options = { + autofocus: true, + hideClose: true, + persistent: true, + removeOnDismissal: false, + eventCallback(aTopic) { + if (aTopic === "showing") { + _this._onPromptShowing(aWarningMessage); + } else if (aTopic === "shown") { + _this._onPromptShown(); + } else if (aTopic === "removed") { + _this._onPromptRemoved(); + } + } + }; + + this._prompt = PopupNotifications.show(this._browser, + OnionAuthUtil.domid.notification, "", + OnionAuthUtil.domid.anchor, + mainAction, [cancelAction], options); + }, + + _onPromptShowing(aWarningMessage) { + let xulDoc = this._browser.ownerDocument; + let descElem = xulDoc.getElementById(OnionAuthUtil.domid.description); + if (descElem) { + // Handle replacement of the onion name within the localized + // string ourselves so we can show the onion name as bold text. + // We do this by splitting the localized string and creating + // several HTML <span> elements. + while (descElem.firstChild) + descElem.removeChild(descElem.firstChild); + + let fmtString = TorStrings.onionServices.authPrompt.description; + let prefix = ""; + let suffix = ""; + const kToReplace = "%S"; + let idx = fmtString.indexOf(kToReplace); + if (idx < 0) { + prefix = fmtString; + } else { + prefix = fmtString.substring(0, idx); + suffix = fmtString.substring(idx + kToReplace.length); + } + + const kHTMLNS = "http://www.w3.org/1999/xhtml"; + let span = xulDoc.createElementNS(kHTMLNS, "span"); + span.textContent = prefix; + descElem.appendChild(span); + span = xulDoc.createElementNS(kHTMLNS, "span"); + span.id = OnionAuthUtil.domid.onionNameSpan; + span.textContent = this._onionName; + descElem.appendChild(span); + span = xulDoc.createElementNS(kHTMLNS, "span"); + span.textContent = suffix; + descElem.appendChild(span); + } + + // Set "Learn More" label and href. + let learnMoreElem = xulDoc.getElementById(OnionAuthUtil.domid.learnMore); + if (learnMoreElem) { + learnMoreElem.setAttribute("value", TorStrings.onionServices.learnMore); + learnMoreElem.setAttribute("href", TorStrings.onionServices.learnMoreURL); + } + + this._showWarning(aWarningMessage); + let checkboxElem = this._getCheckboxElement(); + if (checkboxElem) { + checkboxElem.checked = false; + } + }, + + _onPromptShown() { + let keyElem = this._getKeyElement(); + if (keyElem) { + keyElem.setAttribute("placeholder", + TorStrings.onionServices.authPrompt.keyPlaceholder); + this._boundOnKeyFieldKeyPress = this._onKeyFieldKeyPress.bind(this); + this._boundOnKeyFieldInput = this._onKeyFieldInput.bind(this); + keyElem.addEventListener("keypress", this._boundOnKeyFieldKeyPress); + keyElem.addEventListener("input", this._boundOnKeyFieldInput); + keyElem.focus(); + } + }, + + _onPromptRemoved() { + if (this._boundOnKeyFieldKeyPress) { + let keyElem = this._getKeyElement(); + if (keyElem) { + keyElem.value = ""; + keyElem.removeEventListener("keypress", + this._boundOnKeyFieldKeyPress); + this._boundOnKeyFieldKeyPress = undefined; + keyElem.removeEventListener("input", this._boundOnKeyFieldInput); + this._boundOnKeyFieldInput = undefined; + } + } + }, + + _onKeyFieldKeyPress(aEvent) { + if (aEvent.keyCode == aEvent.DOM_VK_RETURN) { + this._onDone(); + } else if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE) { + this._prompt.remove(); + this._onCancel(); + } + }, + + _onKeyFieldInput(aEvent) { + this._showWarning(undefined); // Remove the warning. + }, + + _onDone() { + let keyElem = this._getKeyElement(); + if (!keyElem) + return; + + let base64key = this._keyToBase64(keyElem.value); + if (!base64key) { + this._showWarning(TorStrings.onionServices.authPrompt.invalidKey); + return; + } + + this._prompt.remove(); + + // Use Torbutton's controller module to add the private key to Tor. + let controllerFailureMsg = + TorStrings.onionServices.authPrompt.failedToSetKey; + try { + let { controller } = + Cu.import("resource://torbutton/modules/tor-control-port.js", {}); + let torController = controller(aError => { + this.show(controllerFailureMsg); + }); + let onionAddr = this._onionName.toLowerCase().replace(/\.onion$/, ""); + let checkboxElem = this._getCheckboxElement(); + let isPermanent = (checkboxElem && checkboxElem.checked); + torController.onionAuthAdd(onionAddr, base64key, isPermanent) + .then(aResponse => { + // Success! Reload the page. + this._browser.sendMessageToActor( + "Browser:Reload", + {}, + "BrowserTab" + ); + }) + .catch(aError => { + if (aError.torMessage) + this.show(aError.torMessage); + else + this.show(controllerFailureMsg); + }); + } catch (e) { + this.show(controllerFailureMsg); + } + }, + + _onCancel() { + // Arrange for an error page to be displayed. + this._browser.messageManager.sendAsyncMessage( + OnionAuthUtil.message.authPromptCanceled, + {failedURI: this._failedURI.spec, + reasonForPrompt: this._reasonForPrompt}); + }, + + _getKeyElement() { + let xulDoc = this._browser.ownerDocument; + return xulDoc.getElementById(OnionAuthUtil.domid.keyElement); + }, + + _getCheckboxElement() { + let xulDoc = this._browser.ownerDocument; + return xulDoc.getElementById(OnionAuthUtil.domid.checkboxElement); + }, + + _showWarning(aWarningMessage) { + let xulDoc = this._browser.ownerDocument; + let warningElem = + xulDoc.getElementById(OnionAuthUtil.domid.warningElement); + let keyElem = this._getKeyElement(); + if (warningElem) { + if (aWarningMessage) { + warningElem.textContent = aWarningMessage; + warningElem.removeAttribute("hidden"); + if (keyElem) + keyElem.className = "invalid"; + } else { + warningElem.setAttribute("hidden", "true"); + if (keyElem) + keyElem.className = ""; + } + } + }, + + // Returns undefined if the key is the wrong length or format. + _keyToBase64(aKeyString) { + if (!aKeyString) + return undefined; + + let base64key; + if (aKeyString.length == 52) { + // The key is probably base32-encoded. Attempt to decode. + // Although base32 specifies uppercase letters, we accept lowercase + // as well because users may type in lowercase or copy a key out of + // a tor onion-auth file (which uses lowercase). + let rawKey; + try { + rawKey = CommonUtils.decodeBase32(aKeyString.toUpperCase()); + } catch (e) {} + + if (rawKey) try { + base64key = btoa(rawKey); + } catch (e) {} + } else if ((aKeyString.length == 44) && + /^[a-zA-Z0-9+/]*=*$/.test(aKeyString)) { + // The key appears to be a correctly formatted base64 value. If not, + // tor will return an error when we try to add the key via the + // control port. + base64key = aKeyString; + } + + return base64key; + }, + }; + + let retval = { + init() { + Services.obs.addObserver(this, OnionAuthUtil.topic.clientAuthMissing); + Services.obs.addObserver(this, OnionAuthUtil.topic.clientAuthIncorrect); + }, + + uninit() { + Services.obs.removeObserver(this, OnionAuthUtil.topic.clientAuthMissing); + Services.obs.removeObserver(this, OnionAuthUtil.topic.clientAuthIncorrect); + }, + + // aSubject is the DOM Window or browser where the prompt should be shown. + // aData contains the .onion name. + observe(aSubject, aTopic, aData) { + if ((aTopic != OnionAuthUtil.topic.clientAuthMissing) && + (aTopic != OnionAuthUtil.topic.clientAuthIncorrect)) { + return; + } + + let browser; + if (aSubject instanceof Ci.nsIDOMWindow) { + let contentWindow = aSubject.QueryInterface(Ci.nsIDOMWindow); + browser = contentWindow.docShell.chromeEventHandler; + } else { + browser = aSubject.QueryInterface(Ci.nsIBrowser); + } + + if (!gBrowser.browsers.some(aBrowser => aBrowser == browser)) { + return; // This window does not contain the subject browser; ignore. + } + + let failedURI = browser.currentURI; + let authPrompt = new OnionServicesAuthPrompt(browser, failedURI, + aTopic, aData); + authPrompt.show(undefined); + } + }; + + return retval; +})(); /* OnionAuthPrompt */ + + +Object.defineProperty(this, "OnionAuthPrompt", { + value: OnionAuthPrompt, + enumerable: true, + writable: false +}); diff --git a/browser/components/onionservices/content/authUtil.jsm b/browser/components/onionservices/content/authUtil.jsm new file mode 100644 index 000000000000..c9d83774da1f --- /dev/null +++ b/browser/components/onionservices/content/authUtil.jsm @@ -0,0 +1,47 @@ +// Copyright (c) 2020, The Tor Project, Inc. + +"use strict"; + +var EXPORTED_SYMBOLS = [ + "OnionAuthUtil", +]; + +var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); + +const OnionAuthUtil = { + topic: { + clientAuthMissing: "tor-onion-services-clientauth-missing", + clientAuthIncorrect: "tor-onion-services-clientauth-incorrect", + }, + message: { + authPromptCanceled: "Tor:OnionServicesAuthPromptCanceled", + }, + domid: { + anchor: "tor-clientauth-notification-icon", + notification: "tor-clientauth", + description: "tor-clientauth-notification-desc", + learnMore: "tor-clientauth-notification-learnmore", + onionNameSpan: "tor-clientauth-notification-onionname", + keyElement: "tor-clientauth-notification-key", + warningElement: "tor-clientauth-warning", + checkboxElement: "tor-clientauth-persistkey-checkbox", + }, + + addCancelMessageListener(aTabContent, aDocShell) { + aTabContent.addMessageListener(this.message.authPromptCanceled, + (aMessage) => { + // Upon cancellation of the client authentication prompt, display + // the appropriate error page. When calling the docShell + // displayLoadError() function, we pass undefined for the failed + // channel so that displayLoadError() can determine that it should + // not display the client authentication prompt a second time. + let failedURI = Services.io.newURI(aMessage.data.failedURI); + let reasonForPrompt = aMessage.data.reasonForPrompt; + let errorCode = + (reasonForPrompt === this.topic.clientAuthMissing) ? + Cr.NS_ERROR_TOR_ONION_SVC_MISSING_CLIENT_AUTH : + Cr.NS_ERROR_TOR_ONION_SVC_BAD_CLIENT_AUTH; + aDocShell.displayLoadError(errorCode, failedURI, undefined, undefined); + }); + }, +}; diff --git a/browser/components/onionservices/content/netError/browser.svg b/browser/components/onionservices/content/netError/browser.svg new file mode 100644 index 000000000000..b4c433b37bbb --- /dev/null +++ b/browser/components/onionservices/content/netError/browser.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="72" height="65" viewBox="0 0 72 65"> + <path fill="context-fill" fill-opacity="context-fill-opacity" d="M0.0 0.0C0.0 0.0 0.0 65.0 0.0 65.0C0.0 65.0 72.0 65.0 72.0 65.0C72.0 65.0 72.0 0.0 72.0 0.0C72.0 0.0 52.9019692 0.0 52.9019692 0.0C52.9019692 0.0 0.0 0.0 0.0 0.0C0.0 0.0 0.0 0.0 0.0 0.0M65.0 58.0C65.0 58.0 6.0 58.0 6.0 58.0C6.0 58.0 6.0 25.0 6.0 25.0C6.0 25.0 65.0 25.0 65.0 25.0C65.0 25.0 65.0 58.0 65.0 58.0C65.0 58.0 65.0 58.0 65.0 58.0M6.0 10.0C6.0 10.0 10.0 10.0 10.0 10.0C10.0 10.0 10.0 14.0 10.0 14.0C10.0 14.0 6.0 14.0 6.0 14.0C6.0 14.0 6.0 10.0 6.0 10.0C6.0 10.0 6.0 10.0 6.0 10.0M14.0 10.0C14.0 10.0 18.0 10.0 18.0 10.0C18.0 10.0 18.0 14.0 18.0 14.0C18.0 14.0 14.0 14.0 14.0 14.0C14.0 14.0 14.0 10.0 14.0 10.0C14.0 10.0 14.0 10.0 14.0 10.0M22.0 10.0C22.0 10.0 26.0 10.0 26.0 10.0C26.0 10.0 26.0 14.0 26.0 14.0C26.0 14.0 22.0 14.0 22.0 14.0C22.0 14.0 22.0 10.0 22.0 10.0C22.0 10.0 22.0 10.0 22.0 10.0" /> +</svg> diff --git a/browser/components/onionservices/content/netError/network.svg b/browser/components/onionservices/content/netError/network.svg new file mode 100644 index 000000000000..808c53dedd09 --- /dev/null +++ b/browser/components/onionservices/content/netError/network.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="72" height="54" viewBox="0 0 72 54"> + <path fill="context-fill" fill-opacity="context-fill-opacity" d="M14.0487805 54.0C6.28990244 54.0 0.0 47.3306322 0.0 39.1034585C0.0 32.0105634 4.68716488 26.0867675 10.9481707 24.585103C10.6902 23.574652 10.5365854 22.5107596 10.5365854 21.4138156C10.5365854 14.7292347 15.6471278 9.3103384 21.9512195 9.3103384C24.8076351 9.3103384 27.4126741 10.4393194 29.4146341 12.2780088C32.1344254 5.0777841 38.77452 0.0 46.5365854 0.0C56.7201249 0.0 64.9756098 8.7536733 64.9756098 19.5517479C64.9756098 20.7691677 64.8471688 21.9453428 64.6463415 23.1013144C69.0576849 26.0679606 72.0 31.2693674 72.0 37.2413909C72.0 46.5256603 64.9510244 54.0 56.195122 54.0C56.195122 54.0 14.0487805 54.0 14.0487805 54.0C14.0487805 54.0 14.0487805 54.0 14.0487805 54.0" /> +</svg> diff --git a/browser/components/onionservices/content/netError/onionNetError.css b/browser/components/onionservices/content/netError/onionNetError.css new file mode 100644 index 000000000000..58117ab93223 --- /dev/null +++ b/browser/components/onionservices/content/netError/onionNetError.css @@ -0,0 +1,65 @@ +/* Copyright (c) 2020, The Tor Project, Inc. */ + +:root { + --grey-70: #38383d; +} + +#onionErrorDiagramContainer { + margin: 60px auto; + width: 460px; /* 3 columns @ 140px plus 2 column gaps @ 20px */ + display: grid; + grid-row-gap: 15px; + grid-column-gap: 20px; + grid-template-columns: 1fr 1fr 1fr; +} + +#onionErrorDiagramContainer > div { + margin: auto; + position: relative; /* needed to allow overlay of the ok or error icon */ +} + +.onionErrorImage { + width: 72px; + height: 72px; + background-position: center; + background-repeat: no-repeat; + -moz-context-properties: fill; + fill: var(--grey-70); +} + +#onionErrorBrowserImage { + background-image: url("browser.svg"); +} + +#onionErrorNetworkImage { + background-image: url("network.svg"); +} + +#onionErrorOnionSiteImage { + background-image: url("onionsite.svg"); +} + +/* rules to support overlay of the ok or error icon */ +.onionErrorImage[status]::after { + content: " "; + position: absolute; + left: -18px; + top: 18px; + width: 36px; + height: 36px; + -moz-context-properties: fill; + fill: var(--in-content-page-background); + background-color: var(--grey-70); + background-repeat: no-repeat; + background-position: center; + border: 3px solid var(--in-content-page-background); + border-radius: 50%; +} + +.onionErrorImage[status="ok"]::after { + background-image: url("chrome://global/skin/icons/check.svg"); +} + +.onionErrorImage[status="error"]::after { + background-image: url("chrome://browser/skin/stop.svg"); +} diff --git a/browser/components/onionservices/content/netError/onionNetError.js b/browser/components/onionservices/content/netError/onionNetError.js new file mode 100644 index 000000000000..8fabb3f38eb7 --- /dev/null +++ b/browser/components/onionservices/content/netError/onionNetError.js @@ -0,0 +1,244 @@ +// Copyright (c) 2020, The Tor Project, Inc. + +"use strict"; + +/* eslint-env mozilla/frame-script */ + +var OnionServicesAboutNetError = { + _selector: { + header: ".title-text", + longDesc: "#errorLongDesc", + learnMoreContainer: "#learnMoreContainer", + learnMoreLink: "#learnMoreLink", + contentContainer: "#errorLongContent", + tryAgainButtonContainer: "#netErrorButtonContainer", + }, + _status: { + ok: "ok", + error: "error", + }, + + _diagramInfoMap: undefined, + + // Public functions (called from outside this file). + // + // This initPage() function may need to be updated if the structure of + // browser/base/content/aboutNetError.xhtml changes. Specifically, it + // references the following elements: + // query string parameter e + // class title-text + // id errorLongDesc + // id learnMoreContainer + // id learnMoreLink + // id errorLongContent + initPage(aDoc) { + const searchParams = new URLSearchParams(aDoc.documentURI.split("?")[1]); + const err = searchParams.get("e"); + + const errPrefix = "onionServices."; + const errName = err.substring(errPrefix.length); + + this._strings = RPMGetTorStrings(); + + const stringsObj = this._strings[errName]; + if (!stringsObj) { + return; + } + + this._insertStylesheet(aDoc); + + const pageTitle = stringsObj.pageTitle; + const header = stringsObj.header; + const longDescription = stringsObj.longDescription; // optional + const learnMoreURL = stringsObj.learnMoreURL; + + if (pageTitle) { + aDoc.title = pageTitle; + } + + if (header) { + const headerElem = aDoc.querySelector(this._selector.header); + if (headerElem) { + headerElem.textContent = header; + } + } + + const ld = aDoc.querySelector(this._selector.longDesc); + if (ld) { + if (longDescription) { + const hexErr = this._hexErrorFromName(errName); + ld.textContent = longDescription.replace("%S", hexErr); + } else { + // This onion service error does not have a long description. Since + // it is set to a generic error string by the code in + // browser/base/content/aboutNetError.js, hide it here. + ld.style.display = "none"; + } + } + + if (learnMoreURL) { + const lmContainer = aDoc.querySelector(this._selector.learnMoreContainer); + if (lmContainer) { + lmContainer.style.display = "block"; + } + const lmLink = lmContainer.querySelector(this._selector.learnMoreLink); + if (lmLink) { + lmLink.setAttribute("href", learnMoreURL); + } + } + + // Remove the "Try Again" button if the user made a typo in the .onion + // address since it is not useful in that case. + if (errName === "badAddress") { + const tryAgainButton = aDoc.querySelector( + this._selector.tryAgainButtonContainer + ); + if (tryAgainButton) { + tryAgainButton.style.display = "none"; + } + } + + this._insertDiagram(aDoc, errName); + }, // initPage() + + _insertStylesheet(aDoc) { + const url = + "chrome://browser/content/onionservices/netError/onionNetError.css"; + let linkElem = aDoc.createElement("link"); + linkElem.rel = "stylesheet"; + linkElem.href = url; + linkElem.type = "text/css"; + aDoc.head.appendChild(linkElem); + }, + + _insertDiagram(aDoc, aErrorName) { + // The onion error diagram consists of a grid of div elements. + // The first row contains three images (Browser, Network, Onionsite) and + // the second row contains labels for the images that are in the first row. + // The _diagramInfoMap describes for each type of onion service error + // whether a small ok or error status icon is overlaid on top of the main + // Browser/Network/Onionsite images. + if (!this._diagramInfoMap) { + this._diagramInfoMap = new Map(); + this._diagramInfoMap.set("descNotFound", { + browser: this._status.ok, + network: this._status.ok, + onionSite: this._status.error, + }); + this._diagramInfoMap.set("descInvalid", { + browser: this._status.ok, + network: this._status.error, + }); + this._diagramInfoMap.set("introFailed", { + browser: this._status.ok, + network: this._status.error, + }); + this._diagramInfoMap.set("rendezvousFailed", { + browser: this._status.ok, + network: this._status.error, + }); + this._diagramInfoMap.set("clientAuthMissing", { + browser: this._status.error, + }); + this._diagramInfoMap.set("clientAuthIncorrect", { + browser: this._status.error, + }); + this._diagramInfoMap.set("badAddress", { + browser: this._status.error, + }); + this._diagramInfoMap.set("introTimedOut", { + browser: this._status.ok, + network: this._status.error, + }); + } + + const diagramInfo = this._diagramInfoMap.get(aErrorName); + + const container = this._createDiv(aDoc, "onionErrorDiagramContainer"); + const imageClass = "onionErrorImage"; + + const browserImage = this._createDiv( + aDoc, + "onionErrorBrowserImage", + imageClass, + container + ); + if (diagramInfo && diagramInfo.browser) { + browserImage.setAttribute("status", diagramInfo.browser); + } + + const networkImage = this._createDiv( + aDoc, + "onionErrorNetworkImage", + imageClass, + container + ); + if (diagramInfo && diagramInfo.network) { + networkImage.setAttribute("status", diagramInfo.network); + } + + const onionSiteImage = this._createDiv( + aDoc, + "onionErrorOnionSiteImage", + imageClass, + container + ); + if (diagramInfo && diagramInfo.onionSite) { + onionSiteImage.setAttribute("status", diagramInfo.onionSite); + } + + let labelDiv = this._createDiv(aDoc, undefined, undefined, container); + labelDiv.textContent = this._strings.errorPage.browser; + labelDiv = this._createDiv(aDoc, undefined, undefined, container); + labelDiv.textContent = this._strings.errorPage.network; + labelDiv = this._createDiv(aDoc, undefined, undefined, container); + labelDiv.textContent = this._strings.errorPage.onionSite; + + const contentContainer = aDoc.querySelector( + this._selector.contentContainer + ); + if (contentContainer) { + contentContainer.insertBefore(container, contentContainer.firstChild); + } + }, // _insertDiagram() + + _createDiv(aDoc, aID, aClass, aParentElem) { + const div = aDoc.createElement("div"); + if (aID) { + div.id = aID; + } + if (aClass) { + div.setAttribute("class", aClass); + } + if (aParentElem) { + aParentElem.appendChild(div); + } + + return div; + }, + + _hexErrorFromName(aErrorName) { + // We do not have access to the original Tor SOCKS error code here, so + // perform a reverse mapping from the error name. + switch (aErrorName) { + case "descNotFound": + return "0xF0"; + case "descInvalid": + return "0xF1"; + case "introFailed": + return "0xF2"; + case "rendezvousFailed": + return "0xF3"; + case "clientAuthMissing": + return "0xF4"; + case "clientAuthIncorrect": + return "0xF5"; + case "badAddress": + return "0xF6"; + case "introTimedOut": + return "0xF7"; + } + + return ""; + }, +}; diff --git a/browser/components/onionservices/content/netError/onionsite.svg b/browser/components/onionservices/content/netError/onionsite.svg new file mode 100644 index 000000000000..1f2777e6acc7 --- /dev/null +++ b/browser/components/onionservices/content/netError/onionsite.svg @@ -0,0 +1,7 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="70" height="63" viewBox="0 0 70 63"> + <g fill="context-fill" fill-opacity="context-fill-opacity"> + <path d="M64.0 2.0C64.0 2.0 4.0 2.0 4.0 2.0C2.8954305 2.0 2.0 2.81148389 2.0 3.8125C2.0 3.8125 2.0 58.1875 2.0 58.1875C2.0 59.1885161 2.8954305 60.0 4.0 60.0C4.0 60.0 36.0 60.0 36.0 60.0C36.0 60.0 36.0 56.375 36.0 56.375C36.0 56.375 6.0 56.375 6.0 56.375C6.0 56.375 6.0 41.875 6.0 41.875C6.0 41.875 38.0 41.875 38.0 41.875C38.0 41.875 38.0 38.25 38.0 38.25C38.0 38.25 6.0 38.25 6.0 38.25C6.0 38.25 6.0 23.75 6.0 23.75C6.0 23.75 62.0 23.75 62.0 23.75C62.0 23.75 62.0 36.4375 62.0 36.4375C62.0 36.4375 66.0 36.4375 66.0 36.4375C66.0 36.4375 66.0 3.8125 66.0 3.8125C66.0 2.81148389 65.1045695 2.0 64.0 2.0C64.0 2.0 64.0 2.0 64.0 2.0M62.0 20.125C62.0 20.125 6.0 20.125 6.0 20.125C6.0 20.125 6.0 5.625 6.0 5.625C6.0 5.625 62.0 5.625 62.0 5.625C62.0 5.625 62.0 20.125 62.0 20.125C62.0 20.125 62.0 20.125 62.0 20.125" /> + <path d="M24.0 47.0C24.0 47.0 24.0 51.0 24.0 51.0C24.0 51.0 20.0 51.0 20.0 51.0C20.0 51.0 20.0 47.0 20.0 47.0C20.0 47.0 24.0 47.0 24.0 47.0C24.0 47.0 24.0 47.0 24.0 47.0M16.0 47.0C16.0 47.0 16.0 51.0 16.0 51.0C16.0 51.0 12.0 51.0 12.0 51.0C12.0 51.0 12.0 47.0 12.0 47.0C12.0 47.0 16.0 47.0 16.0 47.0C16.0 47.0 16.0 47.0 16.0 47.0M56.0 29.0C56.0 29.0 56.0 33.0 56.0 33.0C56.0 33.0 52.0 33.0 52.0 33.0C52.0 33.0 52.0 29.0 52.0 29.0C52.0 29.0 56.0 29.0 56.0 29.0C56.0 29.0 56.0 29.0 56.0 29.0M48.0 29.0C48.0 29.0 48.0 33.0 48.0 33.0C48.0 33.0 12.0 33.0 12.0 33.0C12.0 33.0 12.0 29.0 12.0 29.0C12.0 29.0 48.0 29.0 48.0 29.0C48.0 29.0 48.0 29.0 48.0 29.0M22.0 11.0C22.0 11.0 22.0 15.0 22.0 15.0C22.0 15.0 10.0 15.0 10.0 15.0C10.0 15.0 10.0 11.0 10.0 11.0C10.0 11.0 22.0 11.0 22.0 11.0C22.0 11.0 22.0 11.0 22.0 11.0M70.0 0.0C70.0 0.0 70.0 36.5 70.0 36.5C70.0 36.5 65.0 36.5 65.0 36.5C65.0 36.5 65.0 4.5 65.0 4.5C65.0 4.5 5.0 4.5 5.0 4.5C5.0 4.5 5.0 58.5 5.0 58.5C5.0 58.5 36.0 58.5 36.0 58.5C36.0 58 .5 36.0 63.0 36.0 63.0C36.0 63.0 0.0 63.0 0.0 63.0C0.0 63.0 0.0 0.0 0.0 0.0C0.0 0.0 70.0 0.0 70.0 0.0C70.0 0.0 70.0 0.0 70.0 0.0M32.0 47.0C32.0 47.0 32.0 51.0 32.0 51.0C32.0 51.0 28.0 51.0 28.0 51.0C28.0 51.0 28.0 47.0 28.0 47.0C28.0 47.0 32.0 47.0 32.0 47.0C32.0 47.0 32.0 47.0 32.0 47.0M54.0 11.0C54.0 11.0 54.0 15.0 54.0 15.0C54.0 15.0 50.0 15.0 50.0 15.0C50.0 15.0 50.0 11.0 50.0 11.0C50.0 11.0 54.0 11.0 54.0 11.0C54.0 11.0 54.0 11.0 54.0 11.0M46.0 11.0C46.0 11.0 46.0 15.0 46.0 15.0C46.0 15.0 42.0 15.0 42.0 15.0C42.0 15.0 42.0 11.0 42.0 11.0C42.0 11.0 46.0 11.0 46.0 11.0C46.0 11.0 46.0 11.0 46.0 11.0M38.0 11.0C38.0 11.0 38.0 15.0 38.0 15.0C38.0 15.0 34.0 15.0 34.0 15.0C34.0 15.0 34.0 11.0 34.0 11.0C34.0 11.0 38.0 11.0 38.0 11.0C38.0 11.0 38.0 11.0 38.0 11.0M30.0 11.0C30.0 11.0 30.0 15.0 30.0 15.0C30.0 15.0 26.0 15.0 26.0 15.0C26.0 15.0 26.0 11.0 26.0 11.0C26.0 11.0 30.0 11.0 30.0 11.0C30.0 11.0 30.0 11.0 30.0 11.0" /> + <path d="M61.0 46.0C61.0 46.0 59.0 46.0 59.0 46.0C59.0 46.0 59.0 40.0 59.0 40.0C59.0 38.8954305 58.1045695 38.0 57.0 38.0C57.0 38.0 49.0 38.0 49.0 38.0C47.8954305 38.0 47.0 38.8954305 47.0 40.0C47.0 40.0 47.0 46.0 47.0 46.0C47.0 46.0 45.0 46.0 45.0 46.0C43.8954305 46.0 43.0 46.8954305 43.0 48.0C43.0 48.0 43.0 60.0 43.0 60.0C43.0 61.1045695 43.8954305 62.0 45.0 62.0C45.0 62.0 61.0 62.0 61.0 62.0C62.1045695 62.0 63.0 61.1045695 63.0 60.0C63.0 60.0 63.0 48.0 63.0 48.0C63.0 46.8954305 62.1045695 46.0 61.0 46.0C61.0 46.0 61.0 46.0 61.0 46.0M51.0 42.0C51.0 42.0 55.0 42.0 55.0 42.0C55.0 42.0 55.0 46.0 55.0 46.0C55.0 46.0 51.0 46.0 51.0 46.0C51.0 46.0 51.0 42.0 51.0 42.0C51.0 42.0 51.0 42.0 51.0 42.0M59.0 58.0C59.0 58.0 47.0 58.0 47.0 58.0C47.0 58.0 47.0 50.0 47.0 50.0C47.0 50.0 59.0 50.0 59.0 50.0C59.0 50.0 59.0 58.0 59.0 58.0C59.0 58.0 59.0 58.0 59.0 58.0" /> + </g> +</svg> diff --git a/browser/components/onionservices/content/onionservices.css b/browser/components/onionservices/content/onionservices.css new file mode 100644 index 000000000000..e2621ec8266d --- /dev/null +++ b/browser/components/onionservices/content/onionservices.css @@ -0,0 +1,69 @@ +/* Copyright (c) 2020, The Tor Project, Inc. */ + +@namespace html url("http://www.w3.org/1999/xhtml"); + +html|*#tor-clientauth-notification-onionname { + font-weight: bold; +} + +html|*#tor-clientauth-notification-key { + box-sizing: border-box; + width: 100%; + margin-top: 15px; + padding: 6px; +} + +/* Start of rules adapted from + * browser/components/newtab/css/activity-stream-mac.css (linux and windows + * use the same rules). + */ +html|*#tor-clientauth-notification-key.invalid { + border: 1px solid #D70022; + box-shadow: 0 0 0 1px #D70022, 0 0 0 4px rgba(215, 0, 34, 0.3); +} + +html|*#tor-clientauth-warning { + display: inline-block; + animation: fade-up-tt 450ms; + background: #D70022; + border-radius: 2px; + color: #FFF; + inset-inline-start: 3px; + padding: 5px 12px; + position: relative; + top: 6px; + z-index: 1; +} + +html|*#tor-clientauth-warning[hidden] { + display: none; +} + +html|*#tor-clientauth-warning::before { + background: #D70022; + bottom: -8px; + content: '.'; + height: 16px; + inset-inline-start: 12px; + position: absolute; + text-indent: -999px; + top: -7px; + transform: rotate(45deg); + white-space: nowrap; + width: 16px; + z-index: -1; +} + +@keyframes fade-up-tt { + 0% { + opacity: 0; + transform: translateY(15px); + } + 100% { + opacity: 1; + transform: translateY(0); + } +} +/* End of rules adapted from + * browser/components/newtab/css/activity-stream-mac.css + */ diff --git a/browser/components/onionservices/content/savedKeysDialog.js b/browser/components/onionservices/content/savedKeysDialog.js new file mode 100644 index 000000000000..b1376bbabe85 --- /dev/null +++ b/browser/components/onionservices/content/savedKeysDialog.js @@ -0,0 +1,259 @@ +// Copyright (c) 2020, The Tor Project, Inc. + +"use strict"; + +ChromeUtils.defineModuleGetter( + this, + "TorStrings", + "resource:///modules/TorStrings.jsm" +); + +ChromeUtils.defineModuleGetter( + this, + "controller", + "resource://torbutton/modules/tor-control-port.js" +); + +var gOnionServicesSavedKeysDialog = { + selector: { + dialog: "#onionservices-savedkeys-dialog", + intro: "#onionservices-savedkeys-intro", + tree: "#onionservices-savedkeys-tree", + onionSiteCol: "#onionservices-savedkeys-siteCol", + onionKeyCol: "#onionservices-savedkeys-keyCol", + errorIcon: "#onionservices-savedkeys-errorIcon", + errorMessage: "#onionservices-savedkeys-errorMessage", + removeButton: "#onionservices-savedkeys-remove", + removeAllButton: "#onionservices-savedkeys-removeall", + }, + + _tree: undefined, + _isBusy: false, // true when loading data, deleting a key, etc. + + // Public functions (called from outside this file). + async deleteSelectedKeys() { + this._setBusyState(true); + + const indexesToDelete = []; + const count = this._tree.view.selection.getRangeCount(); + for (let i = 0; i < count; ++i) { + const minObj = {}; + const maxObj = {}; + this._tree.view.selection.getRangeAt(i, minObj, maxObj); + for (let idx = minObj.value; idx <= maxObj.value; ++idx) { + indexesToDelete.push(idx); + } + } + + if (indexesToDelete.length > 0) { + const controllerFailureMsg = + TorStrings.onionServices.authPreferences.failedToRemoveKey; + try { + const torController = controller(aError => { + this._showError(controllerFailureMsg); + }); + + // Remove in reverse index order to avoid issues caused by index changes. + for (let i = indexesToDelete.length - 1; i >= 0; --i) { + await this._deleteOneKey(torController, indexesToDelete[i]); + } + } catch (e) { + if (e.torMessage) { + this._showError(e.torMessage); + } else { + this._showError(controllerFailureMsg); + } + } + } + + this._setBusyState(false); + }, + + async deleteAllKeys() { + this._tree.view.selection.selectAll(); + await this.deleteSelectedKeys(); + }, + + updateButtonsState() { + const haveSelection = this._tree.view.selection.getRangeCount() > 0; + const dialog = document.querySelector(this.selector.dialog); + const removeSelectedBtn = dialog.querySelector(this.selector.removeButton); + removeSelectedBtn.disabled = this._isBusy || !haveSelection; + const removeAllBtn = dialog.querySelector(this.selector.removeAllButton); + removeAllBtn.disabled = this._isBusy || this.rowCount === 0; + }, + + // Private functions. + _onLoad() { + document.mozSubdialogReady = this._init(); + }, + + async _init() { + await this._populateXUL(); + + window.addEventListener("keypress", this._onWindowKeyPress.bind(this)); + + // We don't use await here because we want _loadSavedKeys() to run + // in the background and not block loading of this dialog. + this._loadSavedKeys(); + }, + + async _populateXUL() { + const dialog = document.querySelector(this.selector.dialog); + const authPrefStrings = TorStrings.onionServices.authPreferences; + dialog.setAttribute("title", authPrefStrings.dialogTitle); + + let elem = dialog.querySelector(this.selector.intro); + elem.textContent = authPrefStrings.dialogIntro; + + elem = dialog.querySelector(this.selector.onionSiteCol); + elem.setAttribute("label", authPrefStrings.onionSite); + + elem = dialog.querySelector(this.selector.onionKeyCol); + elem.setAttribute("label", authPrefStrings.onionKey); + + elem = dialog.querySelector(this.selector.removeButton); + elem.setAttribute("label", authPrefStrings.remove); + + elem = dialog.querySelector(this.selector.removeAllButton); + elem.setAttribute("label", authPrefStrings.removeAll); + + this._tree = dialog.querySelector(this.selector.tree); + }, + + async _loadSavedKeys() { + const controllerFailureMsg = + TorStrings.onionServices.authPreferences.failedToGetKeys; + this._setBusyState(true); + + try { + this._tree.view = this; + + const torController = controller(aError => { + this._showError(controllerFailureMsg); + }); + + const keyInfoList = await torController.onionAuthViewKeys(); + if (keyInfoList) { + // Filter out temporary keys. + this._keyInfoList = keyInfoList.filter(aKeyInfo => { + if (!aKeyInfo.Flags) { + return false; + } + + const flags = aKeyInfo.Flags.split(","); + return flags.includes("Permanent"); + }); + + // Sort by the .onion address. + this._keyInfoList.sort((aObj1, aObj2) => { + const hsAddr1 = aObj1.hsAddress.toLowerCase(); + const hsAddr2 = aObj2.hsAddress.toLowerCase(); + if (hsAddr1 < hsAddr2) { + return -1; + } + return hsAddr1 > hsAddr2 ? 1 : 0; + }); + } + + // Render the tree content. + this._tree.rowCountChanged(0, this.rowCount); + } catch (e) { + if (e.torMessage) { + this._showError(e.torMessage); + } else { + this._showError(controllerFailureMsg); + } + } + + this._setBusyState(false); + }, + + // This method may throw; callers should catch errors. + async _deleteOneKey(aTorController, aIndex) { + const keyInfoObj = this._keyInfoList[aIndex]; + await aTorController.onionAuthRemove(keyInfoObj.hsAddress); + this._tree.view.selection.clearRange(aIndex, aIndex); + this._keyInfoList.splice(aIndex, 1); + this._tree.rowCountChanged(aIndex + 1, -1); + }, + + _setBusyState(aIsBusy) { + this._isBusy = aIsBusy; + this.updateButtonsState(); + }, + + _onWindowKeyPress(event) { + if (event.keyCode === KeyEvent.DOM_VK_ESCAPE) { + window.close(); + } else if (event.keyCode === KeyEvent.DOM_VK_DELETE) { + this.deleteSelectedKeys(); + } + }, + + _showError(aMessage) { + const dialog = document.querySelector(this.selector.dialog); + const errorIcon = dialog.querySelector(this.selector.errorIcon); + errorIcon.style.visibility = aMessage ? "visible" : "hidden"; + const errorDesc = dialog.querySelector(this.selector.errorMessage); + errorDesc.textContent = aMessage ? aMessage : ""; + }, + + // XUL tree widget view implementation. + get rowCount() { + return this._keyInfoList ? this._keyInfoList.length : 0; + }, + + getCellText(aRow, aCol) { + let val = ""; + if (this._keyInfoList && aRow < this._keyInfoList.length) { + const keyInfo = this._keyInfoList[aRow]; + if (aCol.id.endsWith("-siteCol")) { + val = keyInfo.hsAddress; + } else if (aCol.id.endsWith("-keyCol")) { + val = keyInfo.typeAndKey; + // Omit keyType because it is always "x25519". + const idx = val.indexOf(":"); + if (idx > 0) { + val = val.substring(idx + 1); + } + } + } + + return val; + }, + + isSeparator(index) { + return false; + }, + + isSorted() { + return false; + }, + + isContainer(index) { + return false; + }, + + setTree(tree) {}, + + getImageSrc(row, column) {}, + + getCellValue(row, column) {}, + + cycleHeader(column) {}, + + getRowProperties(row) { + return ""; + }, + + getColumnProperties(column) { + return ""; + }, + + getCellProperties(row, column) { + return ""; + }, +}; + +window.addEventListener("load", () => gOnionServicesSavedKeysDialog._onLoad()); diff --git a/browser/components/onionservices/content/savedKeysDialog.xhtml b/browser/components/onionservices/content/savedKeysDialog.xhtml new file mode 100644 index 000000000000..3db9bb05ea82 --- /dev/null +++ b/browser/components/onionservices/content/savedKeysDialog.xhtml @@ -0,0 +1,42 @@ +<?xml version="1.0"?> +<!-- Copyright (c) 2020, The Tor Project, Inc. --> + +<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> +<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css" type="text/css"?> +<?xml-stylesheet href="chrome://browser/content/onionservices/authPreferences.css" type="text/css"?> + +<window id="onionservices-savedkeys-dialog" + windowtype="OnionServices:SavedKeys" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + style="width: 45em;"> + + <script src="chrome://browser/content/onionservices/savedKeysDialog.js"/> + + <vbox id="onionservices-savedkeys" class="contentPane" flex="1"> + <label id="onionservices-savedkeys-intro" + control="onionservices-savedkeys-tree"/> + <separator class="thin"/> + <tree id="onionservices-savedkeys-tree" flex="1" hidecolumnpicker="true" + width="750" + style="height: 20em;" + onselect="gOnionServicesSavedKeysDialog.updateButtonsState();"> + <treecols> + <treecol id="onionservices-savedkeys-siteCol" flex="1" persist="width"/> + <splitter class="tree-splitter"/> + <treecol id="onionservices-savedkeys-keyCol" flex="1" persist="width"/> + </treecols> + <treechildren/> + </tree> + <hbox id="onionservices-savedkeys-errorContainer" align="baseline" flex="1"> + <image id="onionservices-savedkeys-errorIcon"/> + <description id="onionservices-savedkeys-errorMessage" flex="1"/> + </hbox> + <separator class="thin"/> + <hbox id="onionservices-savedkeys-buttons"> + <button id="onionservices-savedkeys-remove" disabled="true" + oncommand="gOnionServicesSavedKeysDialog.deleteSelectedKeys();"/> + <button id="onionservices-savedkeys-removeall" + oncommand="gOnionServicesSavedKeysDialog.deleteAllKeys();"/> + </hbox> + </vbox> +</window> diff --git a/browser/components/onionservices/jar.mn b/browser/components/onionservices/jar.mn new file mode 100644 index 000000000000..9d6ce88d1841 --- /dev/null +++ b/browser/components/onionservices/jar.mn @@ -0,0 +1,9 @@ +browser.jar: + content/browser/onionservices/authPreferences.css (content/authPreferences.css) + content/browser/onionservices/authPreferences.js (content/authPreferences.js) + content/browser/onionservices/authPrompt.js (content/authPrompt.js) + content/browser/onionservices/authUtil.jsm (content/authUtil.jsm) + content/browser/onionservices/netError/ (content/netError/*) + content/browser/onionservices/onionservices.css (content/onionservices.css) + content/browser/onionservices/savedKeysDialog.js (content/savedKeysDialog.js) + content/browser/onionservices/savedKeysDialog.xhtml (content/savedKeysDialog.xhtml) diff --git a/browser/components/onionservices/moz.build b/browser/components/onionservices/moz.build new file mode 100644 index 000000000000..7e103239c8d6 --- /dev/null +++ b/browser/components/onionservices/moz.build @@ -0,0 +1 @@ +JAR_MANIFESTS += ['jar.mn'] diff --git a/browser/components/preferences/preferences.xhtml b/browser/components/preferences/preferences.xhtml index 514eba207ca3..2997149dbb05 100644 --- a/browser/components/preferences/preferences.xhtml +++ b/browser/components/preferences/preferences.xhtml @@ -12,6 +12,7 @@ <?xml-stylesheet href="chrome://browser/skin/preferences/search.css"?> <?xml-stylesheet href="chrome://browser/skin/preferences/containers.css"?> <?xml-stylesheet href="chrome://browser/skin/preferences/privacy.css"?> +<?xml-stylesheet href="chrome://browser/content/onionservices/authPreferences.css"?> <?xml-stylesheet href="chrome://browser/content/securitylevel/securityLevelPreferences.css"?> <?xml-stylesheet href="chrome://browser/content/torpreferences/torPreferences.css"?> diff --git a/browser/components/preferences/privacy.inc.xhtml b/browser/components/preferences/privacy.inc.xhtml index df808f9c92f4..d1f6a1010c1c 100644 --- a/browser/components/preferences/privacy.inc.xhtml +++ b/browser/components/preferences/privacy.inc.xhtml @@ -488,6 +488,8 @@ <label id="fips-desc" hidden="true" data-l10n-id="forms-master-pw-fips-desc"></label> </groupbox> +#include ../onionservices/content/authPreferences.inc.xhtml + <!-- The form autofill section is inserted in to this box after the form autofill extension has initialized. --> <groupbox id="formAutofillGroupBox" diff --git a/browser/components/preferences/privacy.js b/browser/components/preferences/privacy.js index ebf3fcef61a1..0fa239a6bab2 100644 --- a/browser/components/preferences/privacy.js +++ b/browser/components/preferences/privacy.js @@ -77,6 +77,12 @@ XPCOMUtils.defineLazyGetter(this, "AlertsServiceDND", function() { } }); +XPCOMUtils.defineLazyScriptGetter( + this, + ["OnionServicesAuthPreferences"], + "chrome://browser/content/onionservices/authPreferences.js" +); + // TODO: module import via ChromeUtils.defineModuleGetter XPCOMUtils.defineLazyScriptGetter( this, @@ -502,6 +508,7 @@ var gPrivacyPane = { this.trackingProtectionReadPrefs(); this.networkCookieBehaviorReadPrefs(); this._initTrackingProtectionExtensionControl(); + OnionServicesAuthPreferences.init(); this._initSecurityLevel(); Services.telemetry.setEventRecordingEnabled("pwmgr", true); diff --git a/browser/themes/shared/notification-icons.inc.css b/browser/themes/shared/notification-icons.inc.css index d36a08777711..e4045a3912be 100644 --- a/browser/themes/shared/notification-icons.inc.css +++ b/browser/themes/shared/notification-icons.inc.css @@ -120,6 +120,9 @@ list-style-image: url(chrome://browser/skin/notification-icons/indexedDB.svg); } +/* Reuse Firefox's login (key) icon for the Tor onion services auth. prompt */ +.popup-notification-icon[popupid="tor-clientauth"], +.tor-clientauth-icon, .popup-notification-icon[popupid="password"], .login-icon { list-style-image: url(chrome://browser/skin/login.svg); diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index cfd021e0e91e..994f7b5890f8 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -3480,6 +3480,7 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI, } } else { // Errors requiring simple formatting + bool isOnionAuthError = false; switch (aError) { case NS_ERROR_MALFORMED_URI: // URI is malformed @@ -3562,10 +3563,44 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI, // HTTP/2 or HTTP/3 stack detected a protocol error error = "networkProtocolError"; break; - + case NS_ERROR_TOR_ONION_SVC_NOT_FOUND: + error = "onionServices.descNotFound"; + break; + case NS_ERROR_TOR_ONION_SVC_IS_INVALID: + error = "onionServices.descInvalid"; + break; + case NS_ERROR_TOR_ONION_SVC_INTRO_FAILED: + error = "onionServices.introFailed"; + break; + case NS_ERROR_TOR_ONION_SVC_REND_FAILED: + error = "onionServices.rendezvousFailed"; + break; + case NS_ERROR_TOR_ONION_SVC_MISSING_CLIENT_AUTH: + error = "onionServices.clientAuthMissing"; + isOnionAuthError = true; + break; + case NS_ERROR_TOR_ONION_SVC_BAD_CLIENT_AUTH: + error = "onionServices.clientAuthIncorrect"; + isOnionAuthError = true; + break; + case NS_ERROR_TOR_ONION_SVC_BAD_ADDRESS: + error = "onionServices.badAddress"; + break; + case NS_ERROR_TOR_ONION_SVC_INTRO_TIMEDOUT: + error = "onionServices.introTimedOut"; + break; default: break; } + + // The presence of aFailedChannel indicates that we arrived here due to a + // failed connection attempt. Note that we will arrive here a second time + // if the user cancels the Tor client auth prompt, but in that case we + // will not have a failed channel and therefore we will not prompt again. + if (isOnionAuthError && aFailedChannel) { + // Display about:blank while the Tor client auth prompt is open. + errorPage.AssignLiteral("blank"); + } } // If the HTTPS-Only Mode upgraded this request and the upgrade might have @@ -3654,6 +3689,20 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI, nsAutoString str; rv = stringBundle->FormatStringFromName(errorDescriptionID, formatStrs, str); + if (NS_FAILED(rv)) { + // As a fallback, check torbutton.properties for the error string. + const char bundleURL[] = "chrome://torbutton/locale/torbutton.properties"; + nsCOMPtr<nsIStringBundleService> stringBundleService = + mozilla::services::GetStringBundleService(); + if (stringBundleService) { + nsCOMPtr<nsIStringBundle> tbStringBundle; + if (NS_SUCCEEDED(stringBundleService->CreateBundle( + bundleURL, getter_AddRefs(tbStringBundle)))) { + rv = tbStringBundle->FormatStringFromName(errorDescriptionID, + formatStrs, str); + } + } + } NS_ENSURE_SUCCESS(rv, rv); messageStr.Assign(str); } @@ -6060,6 +6109,7 @@ nsresult nsDocShell::FilterStatusForErrorPage( aStatus == NS_ERROR_FILE_ACCESS_DENIED || aStatus == NS_ERROR_CORRUPTED_CONTENT || aStatus == NS_ERROR_INVALID_CONTENT_ENCODING || + NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_TOR || NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_SECURITY) { // Errors to be shown for any frame return aStatus; @@ -7849,6 +7899,35 @@ nsresult nsDocShell::CreateContentViewer(const nsACString& aContentType, FireOnLocationChange(this, aRequest, mCurrentURI, locationFlags); } + // Arrange to show a Tor onion service client authentication prompt if + // appropriate. + if ((mLoadType == LOAD_ERROR_PAGE) && failedChannel) { + nsresult status = NS_OK; + if (NS_SUCCEEDED(failedChannel->GetStatus(&status)) && + ((status == NS_ERROR_TOR_ONION_SVC_MISSING_CLIENT_AUTH) || + (status == NS_ERROR_TOR_ONION_SVC_BAD_CLIENT_AUTH))) { + nsAutoCString onionHost; + failedURI->GetHost(onionHost); + const char* topic = (status == NS_ERROR_TOR_ONION_SVC_MISSING_CLIENT_AUTH) + ? "tor-onion-services-clientauth-missing" + : "tor-onion-services-clientauth-incorrect"; + if (XRE_IsContentProcess()) { + nsCOMPtr<nsIBrowserChild> browserChild = GetBrowserChild(); + if (browserChild) { + static_cast<BrowserChild*>(browserChild.get()) + ->SendShowOnionServicesAuthPrompt(onionHost, nsCString(topic)); + } + } else { + nsCOMPtr<nsPIDOMWindowOuter> browserWin = GetWindow(); + nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService(); + if (browserWin && obsSvc) { + obsSvc->NotifyObservers(browserWin, topic, + NS_ConvertUTF8toUTF16(onionHost).get()); + } + } + } + } + return NS_OK; } diff --git a/dom/ipc/BrowserParent.cpp b/dom/ipc/BrowserParent.cpp index 11d5b0b65a5b..32fc5287d947 100644 --- a/dom/ipc/BrowserParent.cpp +++ b/dom/ipc/BrowserParent.cpp @@ -3879,6 +3879,27 @@ mozilla::ipc::IPCResult BrowserParent::RecvShowCanvasPermissionPrompt( return IPC_OK(); } +mozilla::ipc::IPCResult BrowserParent::RecvShowOnionServicesAuthPrompt( + const nsCString& aOnionName, const nsCString& aTopic) { + nsCOMPtr<nsIBrowser> browser = + mFrameElement ? mFrameElement->AsBrowser() : nullptr; + if (!browser) { + // If the tab is being closed, the browser may not be available. + // In this case we can ignore the request. + return IPC_OK(); + } + nsCOMPtr<nsIObserverService> os = services::GetObserverService(); + if (!os) { + return IPC_FAIL_NO_REASON(this); + } + nsresult rv = os->NotifyObservers(browser, aTopic.get(), + NS_ConvertUTF8toUTF16(aOnionName).get()); + if (NS_FAILED(rv)) { + return IPC_FAIL_NO_REASON(this); + } + return IPC_OK(); +} + mozilla::ipc::IPCResult BrowserParent::RecvVisitURI(nsIURI* aURI, nsIURI* aLastVisitedURI, const uint32_t& aFlags) { diff --git a/dom/ipc/BrowserParent.h b/dom/ipc/BrowserParent.h index b8f606e875fd..6829c7d8bb80 100644 --- a/dom/ipc/BrowserParent.h +++ b/dom/ipc/BrowserParent.h @@ -762,6 +762,9 @@ class BrowserParent final : public PBrowserParent, mozilla::ipc::IPCResult RecvShowCanvasPermissionPrompt( const nsCString& aOrigin, const bool& aHideDoorHanger); + mozilla::ipc::IPCResult RecvShowOnionServicesAuthPrompt( + const nsCString& aOnionName, const nsCString& aTopic); + mozilla::ipc::IPCResult RecvSetSystemFont(const nsCString& aFontName); mozilla::ipc::IPCResult RecvGetSystemFont(nsCString* aFontName); diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index f6eff2546600..5bd2ff244bcb 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -585,6 +585,15 @@ parent: bool aNeedCollectSHistory, uint32_t aFlushId, bool aIsFinal, uint32_t aEpoch); + /** + * This function is used to notify the parent that it should display a + * onion services client authentication prompt. + * + * @param aOnionHost The hostname of the .onion that needs authentication. + * @param aTopic The reason for the prompt. + */ + async ShowOnionServicesAuthPrompt(nsCString aOnionHost, nsCString aTopic); + child: async NativeSynthesisResponse(uint64_t aObserverId, nsCString aResponse); async FlushTabState(uint32_t aFlushId, bool aIsFinal); diff --git a/js/xpconnect/src/xpc.msg b/js/xpconnect/src/xpc.msg index d884c6a85999..31e5e75ba35c 100644 --- a/js/xpconnect/src/xpc.msg +++ b/js/xpconnect/src/xpc.msg @@ -253,5 +253,15 @@ XPC_MSG_DEF(NS_ERROR_FINGERPRINTING_URI , "The URI is fingerprinti XPC_MSG_DEF(NS_ERROR_CRYPTOMINING_URI , "The URI is cryptomining") XPC_MSG_DEF(NS_ERROR_SOCIALTRACKING_URI , "The URI is social tracking") +/* Codes related to Tor */ +XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_NOT_FOUND , "Tor onion service descriptor cannot be found") +XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_IS_INVALID , "Tor onion service descriptor is invalid") +XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_INTRO_FAILED , "Tor onion service introduction failed") +XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_REND_FAILED , "Tor onion service rendezvous failed") +XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_MISSING_CLIENT_AUTH, "Tor onion service missing client authorization") +XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_BAD_CLIENT_AUTH , "Tor onion service wrong client authorization") +XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_BAD_ADDRESS , "Tor onion service bad address") +XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_INTRO_TIMEDOUT , "Tor onion service introduction timed out") + /* Profile manager error codes */ XPC_MSG_DEF(NS_ERROR_DATABASE_CHANGED , "Flushing the profiles to disk would have overwritten changes made elsewhere.") diff --git a/netwerk/base/nsSocketTransport2.cpp b/netwerk/base/nsSocketTransport2.cpp index 50c8743f7b97..3e9c8424c6fc 100644 --- a/netwerk/base/nsSocketTransport2.cpp +++ b/netwerk/base/nsSocketTransport2.cpp @@ -215,6 +215,12 @@ nsresult ErrorAccordingToNSPR(PRErrorCode errorCode) { default: if (psm::IsNSSErrorCode(errorCode)) { rv = psm::GetXPCOMFromNSSError(errorCode); + } else { + // If we received a Tor extended error code via SOCKS, pass it through. + nsresult res = nsresult(errorCode); + if (NS_ERROR_GET_MODULE(res) == NS_ERROR_MODULE_TOR) { + rv = res; + } } break; diff --git a/netwerk/socket/nsSOCKSIOLayer.cpp b/netwerk/socket/nsSOCKSIOLayer.cpp index bfc1d4f4dee0..36c6d9f3cb76 100644 --- a/netwerk/socket/nsSOCKSIOLayer.cpp +++ b/netwerk/socket/nsSOCKSIOLayer.cpp @@ -1004,6 +1004,55 @@ PRStatus nsSOCKSSocketInfo::ReadV5ConnectResponseTop() { "08, Address type not supported.")); c = PR_BAD_ADDRESS_ERROR; break; + case 0xF0: // Tor SOCKS5_HS_NOT_FOUND + LOGERROR( + ("socks5: connect failed: F0," + " Tor onion service descriptor can not be found.")); + c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_NOT_FOUND); + break; + case 0xF1: // Tor SOCKS5_HS_IS_INVALID + LOGERROR( + ("socks5: connect failed: F1," + " Tor onion service descriptor is invalid.")); + c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_IS_INVALID); + break; + case 0xF2: // Tor SOCKS5_HS_INTRO_FAILED + LOGERROR( + ("socks5: connect failed: F2," + " Tor onion service introduction failed.")); + c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_INTRO_FAILED); + break; + case 0xF3: // Tor SOCKS5_HS_REND_FAILED + LOGERROR( + ("socks5: connect failed: F3," + " Tor onion service rendezvous failed.")); + c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_REND_FAILED); + break; + case 0xF4: // Tor SOCKS5_HS_MISSING_CLIENT_AUTH + LOGERROR( + ("socks5: connect failed: F4," + " Tor onion service missing client authorization.")); + c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_MISSING_CLIENT_AUTH); + break; + case 0xF5: // Tor SOCKS5_HS_BAD_CLIENT_AUTH + LOGERROR( + ("socks5: connect failed: F5," + " Tor onion service wrong client authorization.")); + c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_BAD_CLIENT_AUTH); + break; + case 0xF6: // Tor SOCKS5_HS_BAD_ADDRESS + LOGERROR( + ("socks5: connect failed: F6," + " Tor onion service bad address.")); + c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_BAD_ADDRESS); + break; + case 0xF7: // Tor SOCKS5_HS_INTRO_TIMEDOUT + LOGERROR( + ("socks5: connect failed: F7," + " Tor onion service introduction timed out.")); + c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_INTRO_TIMEDOUT); + break; + default: LOGERROR(("socks5: connect failed.")); break; diff --git a/toolkit/modules/PopupNotifications.jsm b/toolkit/modules/PopupNotifications.jsm index 7b7eabea6da4..3ffddfb1cd5b 100644 --- a/toolkit/modules/PopupNotifications.jsm +++ b/toolkit/modules/PopupNotifications.jsm @@ -406,6 +406,8 @@ PopupNotifications.prototype = { * will be dismissed instead of removed after running the callback. * - [optional] disabled (boolean): If this is true, the button * will be disabled. + * - [optional] leaveOpen (boolean): If this is true, the notification + * will not be removed after running the callback. * - [optional] disableHighlight (boolean): If this is true, the button * will not apply the default highlight style. * If null, the notification will have a default "OK" action button @@ -1890,6 +1892,10 @@ PopupNotifications.prototype = { this._dismiss(); return; } + + if (action.leaveOpen) { + return; + } } this._remove(notification); diff --git a/toolkit/modules/RemotePageAccessManager.jsm b/toolkit/modules/RemotePageAccessManager.jsm index 076f1d211c0c..e6e707c2b9b6 100644 --- a/toolkit/modules/RemotePageAccessManager.jsm +++ b/toolkit/modules/RemotePageAccessManager.jsm @@ -103,6 +103,7 @@ let RemotePageAccessManager = { RPMPrefIsLocked: ["security.tls.version.min"], RPMAddToHistogram: ["*"], RPMGetHttpResponseHeader: ["*"], + RPMGetTorStrings: ["*"], }, "about:newinstall": { RPMGetUpdateChannel: ["*"], diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/frame-script.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/frame-script.js index dd5c5fdbe1b0..464e0f654262 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/frame-script.js +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/frame-script.js @@ -38,5 +38,6 @@ module.exports = { RPMAddToHistogram: false, RPMRemoveMessageListener: false, RPMGetHttpResponseHeader: false, + RPMGetTorStrings: false, }, }; diff --git a/xpcom/base/ErrorList.py b/xpcom/base/ErrorList.py index 5451127bcffe..2086aeee3ba4 100755 --- a/xpcom/base/ErrorList.py +++ b/xpcom/base/ErrorList.py @@ -85,6 +85,7 @@ modules["URL_CLASSIFIER"] = Mod(42) # ErrorResult gets its own module to reduce the chance of someone accidentally # defining an error code matching one of the ErrorResult ones. modules["ERRORRESULT"] = Mod(43) +modules["TOR"] = Mod(44) # NS_ERROR_MODULE_GENERAL should be used by modules that do not # care if return code values overlap. Callers of methods that @@ -1179,6 +1180,27 @@ with modules["ERRORRESULT"]: errors["NS_ERROR_INTERNAL_ERRORRESULT_RANGEERROR"] = FAILURE(5) +# ======================================================================= +# 44: Tor-specific error codes. +# ======================================================================= +with modules["TOR"]: + # Tor onion service descriptor can not be found. + errors["NS_ERROR_TOR_ONION_SVC_NOT_FOUND"] = FAILURE(1) + # Tor onion service descriptor is invalid. + errors["NS_ERROR_TOR_ONION_SVC_IS_INVALID"] = FAILURE(2) + # Tor onion service introduction failed. + errors["NS_ERROR_TOR_ONION_SVC_INTRO_FAILED"] = FAILURE(3) + # Tor onion service rendezvous failed. + errors["NS_ERROR_TOR_ONION_SVC_REND_FAILED"] = FAILURE(4) + # Tor onion service missing client authorization. + errors["NS_ERROR_TOR_ONION_SVC_MISSING_CLIENT_AUTH"] = FAILURE(5) + # Tor onion service wrong client authorization. + errors["NS_ERROR_TOR_ONION_SVC_BAD_CLIENT_AUTH"] = FAILURE(6) + # Tor onion service bad address. + errors["NS_ERROR_TOR_ONION_SVC_BAD_ADDRESS"] = FAILURE(7) + # Tor onion service introduction timed out. + errors["NS_ERROR_TOR_ONION_SVC_INTRO_TIMEDOUT"] = FAILURE(8) + # ======================================================================= # 51: NS_ERROR_MODULE_GENERAL # =======================================================================
1 0
0 0
[tor-browser/tor-browser-80.0b2-10.0-1] Bug 27604: Fix addon issues when moving TB directory
by gk@torproject.org 17 Aug '20

17 Aug '20
commit 4dc1ca132c701c5332c4b28921d40e2f90cfb986 Author: Alex Catarineu <acat(a)torproject.org> Date: Wed Oct 30 10:44:48 2019 +0100 Bug 27604: Fix addon issues when moving TB directory --- toolkit/mozapps/extensions/internal/XPIProvider.jsm | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm index a27888278f77..78c0b0f7c702 100644 --- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -485,7 +485,7 @@ class XPIState { // Builds prior to be 1512436 did not include the rootURI property. // If we're updating from such a build, add that property now. - if (!("rootURI" in this) && this.file) { + if (this.file) { this.rootURI = getURIForResourceInFile(this.file, "").spec; } @@ -498,7 +498,10 @@ class XPIState { saved.currentModifiedTime != this.lastModifiedTime ) { this.lastModifiedTime = saved.currentModifiedTime; - } else if (saved.currentModifiedTime === null) { + } else if ( + saved.currentModifiedTime === null && + (!this.file || !this.file.exists()) + ) { this.missing = true; } } @@ -1439,6 +1442,7 @@ var XPIStates = { if (oldState[loc.name]) { loc.restore(oldState[loc.name]); + changed = changed || loc.path != oldState[loc.name].path; } changed = changed || loc.changed;
1 0
0 0
  • ← Newer
  • 1
  • ...
  • 1243
  • 1244
  • 1245
  • 1246
  • 1247
  • 1248
  • 1249
  • ...
  • 1861
  • Older →

HyperKitty Powered by HyperKitty version 1.3.12.