tbb-commits
Threads by month
- ----- 2026 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- 1 participants
- 21337 discussions
[tor-launcher/master] Bug 40679: Missing features on first-time launch in esr91
by gk@torproject.org 19 Jan '22
by gk@torproject.org 19 Jan '22
19 Jan '22
commit d09cfa334a731e705568baf1cd75411b42db04fa
Author: Richard Pospesel <richard(a)torproject.org>
Date: Fri Dec 17 16:59:48 2021 +0100
Bug 40679: Missing features on first-time launch in esr91
- updated tor controller connect calls to use torbutton's new
async api
- fixes tor-browser#40679
---
src/components/tl-protocol.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/tl-protocol.js b/src/components/tl-protocol.js
index cdf5894..f5dddeb 100644
--- a/src/components/tl-protocol.js
+++ b/src/components/tl-protocol.js
@@ -775,7 +775,7 @@ TorProtocolService.prototype =
var conn;
try {
const avoidCache = true;
- conn = controller(e => { throw e; }, avoidCache);
+ conn = await controller(avoidCache);
if (!aIsEventConnection && TorLauncherUtil.shouldStartAndOwnTor &&
!TorLauncherUtil.shouldOnlyConfigureTor)
1
0
[tor-browser/tor-browser-91.5.0esr-11.5-1] fixup! Bug 10760: Integrate TorButton to TorBrowser core
by gk@torproject.org 19 Jan '22
by gk@torproject.org 19 Jan '22
19 Jan '22
commit 2a8908bbdcbeb9aeec735e8a833a5650589653b9
Author: Georg Koppen <gk(a)torproject.org>
Date: Wed Jan 19 13:37:52 2022 +0000
fixup! Bug 10760: Integrate TorButton to TorBrowser core
---
toolkit/torproject/torbutton | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/toolkit/torproject/torbutton b/toolkit/torproject/torbutton
index 29445428ee7c..a7f607351517 160000
--- a/toolkit/torproject/torbutton
+++ b/toolkit/torproject/torbutton
@@ -1 +1 @@
-Subproject commit 29445428ee7c1e033d00d9332983b895dccc052d
+Subproject commit a7f6073515175a1f2d7a2bca1eaec2bfaff03c0c
1
0
[tor-browser/tor-browser-91.5.0esr-11.5-1] fixup! Bug 27476: Implement about:torconnect captive portal within Tor Browser
by gk@torproject.org 19 Jan '22
by gk@torproject.org 19 Jan '22
19 Jan '22
commit eefa8951d7eabcb2b079cb0719bbfc8daff2fc24
Author: Richard Pospesel <richard(a)torproject.org>
Date: Tue Dec 21 17:05:49 2021 +0100
fixup! Bug 27476: Implement about:torconnect captive portal within Tor Browser
---
browser/base/content/utilityOverlay.js | 12 +++++++++---
browser/modules/TorConnect.jsm | 11 ++++++-----
2 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/browser/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js
index 3d22093119ca..5f629dece94e 100644
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -337,11 +337,17 @@ function openUILinkIn(
aPostData,
aReferrerInfo
) {
-
// make sure users are not faced with the scary red 'tor isn't working' screen
// if they navigate to about:tor before bootstrapped
- if (url === "about:tor" && TorConnect.shouldShowTorConnect) {
- url = `about:torconnect?redirect=${encodeURIComponent("about:tor")}`;
+ //
+ // fixes tor-browser#40752
+ // new tabs also redirect to about:tor if browser.newtabpage.enabled is true
+ // otherwise they go to about:blank
+ if (TorConnect.shouldShowTorConnect) {
+ if (url === "about:tor" ||
+ (url === "about:newtab" && Services.prefs.getBoolPref("browser.newtabpage.enabled", false))) {
+ url = TorConnect.getRedirectURL(url);
+ }
}
var params;
diff --git a/browser/modules/TorConnect.jsm b/browser/modules/TorConnect.jsm
index 7c8580b5d8a9..c7ab480e2be0 100644
--- a/browser/modules/TorConnect.jsm
+++ b/browser/modules/TorConnect.jsm
@@ -587,6 +587,10 @@ const TorConnect = (() => {
);
},
+ getRedirectURL: function(url) {
+ return `about:torconnect?redirect=${encodeURIComponent(url)}`;
+ },
+
// called from browser.js on browser startup, passed in either the user's homepage(s)
// or uris passed via command-line; we want to replace them with about:torconnect uris
// which redirect after bootstrapping
@@ -628,13 +632,10 @@ const TorConnect = (() => {
let uris = uriStrings.map(uriStringToUri);
// assume we have a valid uri and generate an about:torconnect redirect uri
- let uriToRedirectUri = (uri) => {
- return`about:torconnect?redirect=${encodeURIComponent(uri.spec)}`;
- };
- let redirectUris = uris.map(uriToRedirectUri);
+ let redirectUrls = uris.map((uri) => this.getRedirectURL(uri.spec));
console.log(`TorConnect: Will load after bootstrap => [${uris.map((uri) => {return uri.spec;}).join(", ")}]`);
- return redirectUris;
+ return redirectUrls;
},
};
retval.init();
1
0
commit a7f6073515175a1f2d7a2bca1eaec2bfaff03c0c
Author: Georg Koppen <gk(a)torproject.org>
Date: Wed Jan 19 13:35:53 2022 +0000
Translations update
---
chrome/locale/ar/aboutTor.dtd | 28 ----------------------------
chrome/locale/bn-BD/aboutTor.dtd | 28 ----------------------------
chrome/locale/ca/aboutTor.dtd | 28 ----------------------------
chrome/locale/cs/aboutTor.dtd | 28 ----------------------------
chrome/locale/da/aboutTor.dtd | 28 ----------------------------
chrome/locale/de/aboutTor.dtd | 28 ----------------------------
chrome/locale/el/aboutTor.dtd | 28 ----------------------------
chrome/locale/el/torbutton.dtd | 6 +++---
chrome/locale/es-AR/aboutTor.dtd | 28 ----------------------------
chrome/locale/es-ES/aboutTor.dtd | 28 ----------------------------
chrome/locale/eu/aboutTor.dtd | 28 ----------------------------
chrome/locale/fa/aboutTor.dtd | 28 ----------------------------
chrome/locale/fr/aboutTor.dtd | 28 ----------------------------
chrome/locale/fr/torbutton.dtd | 2 +-
chrome/locale/ga-IE/aboutTor.dtd | 28 ----------------------------
chrome/locale/he/aboutTor.dtd | 28 ----------------------------
chrome/locale/hu/aboutTor.dtd | 28 ----------------------------
chrome/locale/id/aboutTor.dtd | 28 ----------------------------
chrome/locale/id/torbutton.dtd | 2 +-
chrome/locale/is/aboutTor.dtd | 28 ----------------------------
chrome/locale/it/aboutTor.dtd | 28 ----------------------------
chrome/locale/ja/aboutTor.dtd | 28 ----------------------------
chrome/locale/ja/torbutton.dtd | 4 ++--
chrome/locale/ka/aboutTor.dtd | 28 ----------------------------
chrome/locale/ko/aboutTor.dtd | 28 ----------------------------
chrome/locale/lt/aboutTor.dtd | 28 ----------------------------
chrome/locale/lt/torbutton.dtd | 4 ++--
chrome/locale/mk/aboutTor.dtd | 28 ----------------------------
chrome/locale/mk/torbutton.dtd | 4 ++--
chrome/locale/ms/aboutTor.dtd | 28 ----------------------------
chrome/locale/my/aboutTor.dtd | 28 ----------------------------
chrome/locale/nb-NO/aboutTor.dtd | 28 ----------------------------
chrome/locale/nl/aboutTor.dtd | 28 ----------------------------
chrome/locale/nl/torbutton.dtd | 4 ++--
chrome/locale/pl/aboutTor.dtd | 28 ----------------------------
chrome/locale/pt-BR/aboutTor.dtd | 28 ----------------------------
chrome/locale/ro/aboutTor.dtd | 28 ----------------------------
chrome/locale/ru/aboutTor.dtd | 28 ----------------------------
chrome/locale/sv-SE/aboutTor.dtd | 28 ----------------------------
chrome/locale/th/aboutTor.dtd | 28 ----------------------------
chrome/locale/tr/aboutTor.dtd | 28 ----------------------------
chrome/locale/vi/aboutTor.dtd | 28 ----------------------------
chrome/locale/zh-CN/aboutTor.dtd | 28 ----------------------------
chrome/locale/zh-CN/torbutton.dtd | 4 ++--
chrome/locale/zh-TW/aboutTor.dtd | 30 +-----------------------------
chrome/locale/zh-TW/torbutton.properties | 2 +-
46 files changed, 17 insertions(+), 1053 deletions(-)
diff --git a/chrome/locale/ar/aboutTor.dtd b/chrome/locale/ar/aboutTor.dtd
index 60f87894..00f2f913 100644
--- a/chrome/locale/ar/aboutTor.dtd
+++ b/chrome/locale/ar/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "اشترك للحصول على أخبار تور.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor متاح مجاناً بفضل تبرعات من أشخاص مثلك">
<!ENTITY aboutTor.donationBanner.buttonA "تبرع الآن">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "HANDS\nOFF\nMY\nDATA">
-<!ENTITY aboutTor.yec.motto "الخصوصية هي حق من حقوق الإنسان">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "سيتم مطابقة تبرعك بواسطة Friends of Tor ، حتى 150000 دولار.">
diff --git a/chrome/locale/bn-BD/aboutTor.dtd b/chrome/locale/bn-BD/aboutTor.dtd
index 0808560c..e52c4b7a 100644
--- a/chrome/locale/bn-BD/aboutTor.dtd
+++ b/chrome/locale/bn-BD/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "টর নিউজ-এর জন্য সাইন আপ করুন ।">
<!ENTITY aboutTor.donationBanner.freeToUse "আপনার মতো মানুষদের দানের জন্যই Tor বিনামূল্যে ব্যবহার করা যায়">
<!ENTITY aboutTor.donationBanner.buttonA "এখুনি দান করুন! ">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "HANDS\nOFF\nMY\nDATA">
-<!ENTITY aboutTor.yec.motto "গোপনীয়তা একটি মানুষের অধিকার">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "তোমার অনুদানের সমান পরিমাণ অনুদান $১,৫০,০০০ পর্যন্ত দিলে টরের বন্ধুরা তার সমান অনুদান টরকে দিবে।">
diff --git a/chrome/locale/ca/aboutTor.dtd b/chrome/locale/ca/aboutTor.dtd
index db8d2753..0741dd00 100644
--- a/chrome/locale/ca/aboutTor.dtd
+++ b/chrome/locale/ca/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Inscriviu-vos a les noticies de Tor.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor és d'ús gratuït gràcies als donatius de persones com vós.">
<!ENTITY aboutTor.donationBanner.buttonA "Feu una donació">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "HANDS\nOFF\nMY\nDATA">
-<!ENTITY aboutTor.yec.motto "La privadesa és un dret humà">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Amics del Tor igualarà la vostra donació fins a 150.000 dòlars.">
diff --git a/chrome/locale/cs/aboutTor.dtd b/chrome/locale/cs/aboutTor.dtd
index eaddc377..96eaad26 100644
--- a/chrome/locale/cs/aboutTor.dtd
+++ b/chrome/locale/cs/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Přihlaste se k odběru zpravodaje Toru.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor je zdarma k použití díky darům od lidí jako jste vy.">
<!ENTITY aboutTor.donationBanner.buttonA "Přispějte">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "RUCE\nPRYČ\nOD\nMÝCH\nDAT">
-<!ENTITY aboutTor.yec.motto "Soukromí je lidské právo">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Váš dar bude dorovnán společností Friends of Tor, a to až do výše 150 000 $.">
diff --git a/chrome/locale/da/aboutTor.dtd b/chrome/locale/da/aboutTor.dtd
index 62a0faa8..09c87f8c 100644
--- a/chrome/locale/da/aboutTor.dtd
+++ b/chrome/locale/da/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Tilmeld Tor-nyheder.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor er gratis at bruge takke være donationer fra personer som dig.">
<!ENTITY aboutTor.donationBanner.buttonA "Donér nu">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "HANDS\nOFF\nMY\nDATA">
-<!ENTITY aboutTor.yec.motto "Privatliv er en menneskeret">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Din donation vil blive matchet af venner af Tor, op til $150.000.">
diff --git a/chrome/locale/de/aboutTor.dtd b/chrome/locale/de/aboutTor.dtd
index b602df14..65f3834a 100644
--- a/chrome/locale/de/aboutTor.dtd
+++ b/chrome/locale/de/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Tor-Nachrichten abonnieren.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor ist aufgrund von Spenden von Leuten wie dir frei nutzbar.">
<!ENTITY aboutTor.donationBanner.buttonA "Spende jetzt">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "HÄNDE\nWEG\nVON MEINEN\nDATEN">
-<!ENTITY aboutTor.yec.motto "Datenschutz ist ein Menschenrecht">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Deine Spende wird von Friends of Tor verdoppelt, bis zu 150.000 $.">
diff --git a/chrome/locale/el/aboutTor.dtd b/chrome/locale/el/aboutTor.dtd
index 43179324..bc3f7546 100644
--- a/chrome/locale/el/aboutTor.dtd
+++ b/chrome/locale/el/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Εγγραφτείτε για τα νέα του Tor.">
<!ENTITY aboutTor.donationBanner.freeToUse "Το Tor είναι δωρεάν επειδή στηρίζεται σε δωρεές από άτομα σαν κι εσάς.">
<!ENTITY aboutTor.donationBanner.buttonA "Κάνε μια δωρεά τώρα">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "ΚΑΤΩ ΤΑ\nΧΕΡΙΑ\nΑΠΟ ΤΑ\nΔΕΔΟΜΕΝΑ ΜΟΥ">
-<!ENTITY aboutTor.yec.motto "Η ιδιωτικότητα είναι ανθρώπινο δικαίωμα ">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Η Friends of Tor θα δωρίσει το ίδιο ποσό με τη δωρεά σας, μέχρι $150.000.">
diff --git a/chrome/locale/el/torbutton.dtd b/chrome/locale/el/torbutton.dtd
index b39def2c..2b43207e 100644
--- a/chrome/locale/el/torbutton.dtd
+++ b/chrome/locale/el/torbutton.dtd
@@ -1,8 +1,8 @@
<!ENTITY torbutton.context_menu.new_identity "Νέα Ταυτότητα">
-<!ENTITY torbutton.context_menu.new_identity_sentence_case "New identity">
+<!ENTITY torbutton.context_menu.new_identity_sentence_case "Νέα ταυτότητα">
<!ENTITY torbutton.context_menu.new_identity_key "I">
<!ENTITY torbutton.context_menu.new_circuit "Νέο κύκλωμα Tor για αυτήν την ιστοσελίδα">
-<!ENTITY torbutton.context_menu.new_circuit_sentence_case "New tor circuit for this site">
+<!ENTITY torbutton.context_menu.new_circuit_sentence_case "Νέο κύκλωμα Tor για αυτό τον ιστότοπο">
<!ENTITY torbutton.context_menu.new_circuit_key "C">
<!ENTITY torbutton.context_menu.networksettings "Ρυθμίσεις του Δικτύου Tor...">
<!ENTITY torbutton.context_menu.networksettings.key "N">
@@ -47,7 +47,7 @@
<!ENTITY torbutton.prefs.sec_custom_summary "Οι προσαρμοσμένες προτιμήσεις του browser σας έχουν οδηγήσει σε ασυνήθιστες ρυθμίσεις ασφάλειας. Για λόγους ασφαλείας και ιδιωτικότητας, προτείνουμε να επιλέξετε ένα από τα προεπιλεγμένα επίπεδα ασφάλειας.">
<!ENTITY torbutton.prefs.sec_restore_defaults "Επαναφορά προεπιλογών">
<!ENTITY torbutton.prefs.sec_advanced_security_settings "Ρυθμίσεις ασφαλείας για προχωρημένους...">
-<!ENTITY torbutton.prefs.sec_change "Change…">
+<!ENTITY torbutton.prefs.sec_change "Αλλαγή...">
<!ENTITY torbutton.circuit_display.title "Κύκλωμα Tor">
<!ENTITY torbutton.circuit_display.new_circuit "Νέο κύκλωμα για αυτή την ιστοσελίδα">
diff --git a/chrome/locale/es-AR/aboutTor.dtd b/chrome/locale/es-AR/aboutTor.dtd
index 70d667bd..0c4ebb64 100644
--- a/chrome/locale/es-AR/aboutTor.dtd
+++ b/chrome/locale/es-AR/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Registrate en Tor News.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor puede ser usado libremente gracias a las donaciones de personas como vos.">
<!ENTITY aboutTor.donationBanner.buttonA "Doná ahora">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "NO\nTOQUÉS\nMIS\nDATOS">
-<!ENTITY aboutTor.yec.motto "La privacidad es un derecho humano">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Tu donación va a ser igualada por Amigos de Tor hasta USD 150.000">
diff --git a/chrome/locale/es-ES/aboutTor.dtd b/chrome/locale/es-ES/aboutTor.dtd
index 491c547a..0671a826 100644
--- a/chrome/locale/es-ES/aboutTor.dtd
+++ b/chrome/locale/es-ES/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Inscríbete en Tor News.">
<!ENTITY aboutTor.donationBanner.freeToUse "Se puede usar Tor libremente por las donaciones de personas como tu.">
<!ENTITY aboutTor.donationBanner.buttonA "Dona ahora.">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "NO\nTOQUES\nMIS\nDATOS">
-<!ENTITY aboutTor.yec.motto "La privacidad es un derecho humano.">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Tu donación será igualada por Amigos de Tor hasta $150.000.">
diff --git a/chrome/locale/eu/aboutTor.dtd b/chrome/locale/eu/aboutTor.dtd
index 75ec4f0b..b115af74 100644
--- a/chrome/locale/eu/aboutTor.dtd
+++ b/chrome/locale/eu/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Harpidetu Tor berrietara">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor is free to use because of donations from people like you.">
<!ENTITY aboutTor.donationBanner.buttonA "Egin dohaintza orain">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "HANDS\nOFF\nMY\nDATA">
-<!ENTITY aboutTor.yec.motto "Privacy is a human right">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Your donation will be matched by Friends of Tor, up to $150,000.">
diff --git a/chrome/locale/fa/aboutTor.dtd b/chrome/locale/fa/aboutTor.dtd
index c2438d36..44e1efbc 100644
--- a/chrome/locale/fa/aboutTor.dtd
+++ b/chrome/locale/fa/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "ثبتنام برای اخبار Tor.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor برای استفاده رایگان است، این به خاطر حمایت افرادی مانند شماست.">
<!ENTITY aboutTor.donationBanner.buttonA "اکنون حمایت کنید">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "دست\nاز\nاطلاعات\nمن\nبردارید">
-<!ENTITY aboutTor.yec.motto "حریم خصوصی یک حق انسانی است">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "کمک مالی شما با دوستان تور تا سقف 150000 دلار مطابقت داده می شود.">
diff --git a/chrome/locale/fr/aboutTor.dtd b/chrome/locale/fr/aboutTor.dtd
index 4b0fbbd8..75b45004 100644
--- a/chrome/locale/fr/aboutTor.dtd
+++ b/chrome/locale/fr/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Inscrivez-vous aux nouvelles de Tor.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor peut être utilisé gratuitement grâce aux dons de personnes telles que vous.">
<!ENTITY aboutTor.donationBanner.buttonA "Faites un don maintenant">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "NE TOUCHEZ\nPAS\nÀ MES\nDONNÉES">
-<!ENTITY aboutTor.yec.motto "La vie privée est un droit de la personne">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Votre don sera égalé par les Amis de Tor à concurrence de 150 000 $.">
diff --git a/chrome/locale/fr/torbutton.dtd b/chrome/locale/fr/torbutton.dtd
index d740bc37..1ba569b7 100644
--- a/chrome/locale/fr/torbutton.dtd
+++ b/chrome/locale/fr/torbutton.dtd
@@ -52,5 +52,5 @@
<!ENTITY torbutton.circuit_display.new_circuit "Nouveau circuit pour ce site">
<!-- Onion services strings. Strings are kept here for ease of translation. -->
-<!ENTITY torbutton.onionServices.authPrompt.tooltip "Ouvrir l’invite d’authentification du client du service oignon">
+<!ENTITY torbutton.onionServices.authPrompt.tooltip "Ouvrir l’invite d’authentification client du service oignon">
<!ENTITY torbutton.onionServices.authPrompt.persistCheckboxLabel "Mémoriser cette clé">
diff --git a/chrome/locale/ga-IE/aboutTor.dtd b/chrome/locale/ga-IE/aboutTor.dtd
index 88365aed..8f03245a 100644
--- a/chrome/locale/ga-IE/aboutTor.dtd
+++ b/chrome/locale/ga-IE/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Cláraigh le Nuachtlitir Tor.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tá Tor saor in aisce a bhuí le bronntanais airgid ó dhaoine cosúil leatsa.">
<!ENTITY aboutTor.donationBanner.buttonA "Tabhair síntiús airgid anois">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "HANDS\nOFF\nMY\nDATA">
-<!ENTITY aboutTor.yec.motto "Is buncheart daonna é an príobháideachas">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Your donation will be matched by Friends of Tor, up to $150,000.">
diff --git a/chrome/locale/he/aboutTor.dtd b/chrome/locale/he/aboutTor.dtd
index c48ae2b7..520d773b 100644
--- a/chrome/locale/he/aboutTor.dtd
+++ b/chrome/locale/he/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "הירשם עבור חדשות Tor.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor חינמי לשימוש בגלל תרומות מאנשים כמוך.">
<!ENTITY aboutTor.donationBanner.buttonA "תרום עכשיו">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "HANDS\nOFF\nMY\nDATA">
-<!ENTITY aboutTor.yec.motto "פרטיות היא זכות אדם">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "תרומתך תוכפל על ידי החברים של Tor, עד סכום של $150,000">
diff --git a/chrome/locale/hu/aboutTor.dtd b/chrome/locale/hu/aboutTor.dtd
index bfd3e056..0ea02599 100644
--- a/chrome/locale/hu/aboutTor.dtd
+++ b/chrome/locale/hu/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Iratkozzon fel a Tor hírekhez.">
<!ENTITY aboutTor.donationBanner.freeToUse "A Tor ingyenes az Önhöz hasonló személyek támogatásai miatt.">
<!ENTITY aboutTor.donationBanner.buttonA "Támogasson most">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "HANDS\nOFF\nMY\nDATA">
-<!ENTITY aboutTor.yec.motto "A magánélet emberi jog">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "A támogatásoddal egyező összeget ad a Friends of Tor, 150 000 dollárig.">
diff --git a/chrome/locale/id/aboutTor.dtd b/chrome/locale/id/aboutTor.dtd
index a6663ba9..be1ecb07 100644
--- a/chrome/locale/id/aboutTor.dtd
+++ b/chrome/locale/id/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Daftar untuk mendapatkan Berita Tor.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor bebas digunakan karena donasi dari orang-orang seperti Anda.">
<!ENTITY aboutTor.donationBanner.buttonA "Donasi Sekarang">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "Jauhi\nData\nSaya">
-<!ENTITY aboutTor.yec.motto "Privasi adalah sebuah hak asasi manusia">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Donasi Anda akan disesuaikan oleh "Friends of Tor", hingga $150.000.">
diff --git a/chrome/locale/id/torbutton.dtd b/chrome/locale/id/torbutton.dtd
index dbc6b90f..399c1624 100644
--- a/chrome/locale/id/torbutton.dtd
+++ b/chrome/locale/id/torbutton.dtd
@@ -2,7 +2,7 @@
<!ENTITY torbutton.context_menu.new_identity_sentence_case "Identitas baru">
<!ENTITY torbutton.context_menu.new_identity_key "I">
<!ENTITY torbutton.context_menu.new_circuit "Sirkuit Tor Baru untuk Situs ini">
-<!ENTITY torbutton.context_menu.new_circuit_sentence_case "New tor circuit for this site">
+<!ENTITY torbutton.context_menu.new_circuit_sentence_case "Sirkuit tor baru untuk situs ini">
<!ENTITY torbutton.context_menu.new_circuit_key "C">
<!ENTITY torbutton.context_menu.networksettings "Pengaturan Jaringan Tor…">
<!ENTITY torbutton.context_menu.networksettings.key "N">
diff --git a/chrome/locale/is/aboutTor.dtd b/chrome/locale/is/aboutTor.dtd
index 84f950bc..14bad9ac 100644
--- a/chrome/locale/is/aboutTor.dtd
+++ b/chrome/locale/is/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Skráðu þig til að fá Tor-fréttir.">
<!ENTITY aboutTor.donationBanner.freeToUse "Öllum er frjálst að nota Tor vegna styrkja frá fólki eins og þér.">
<!ENTITY aboutTor.donationBanner.buttonA "Styrkja núna">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "HANDS\nOFF\nMY\nDATA">
-<!ENTITY aboutTor.yec.motto "Friðhelgi persónuupplýsinga er mannréttindi">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Styrkur frá þér verður jafnaður upp af Friends of Tor, allt að $150,000.">
diff --git a/chrome/locale/it/aboutTor.dtd b/chrome/locale/it/aboutTor.dtd
index 29d6ae12..34fe8006 100644
--- a/chrome/locale/it/aboutTor.dtd
+++ b/chrome/locale/it/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Registrati alle Tor News.">
<!ENTITY aboutTor.donationBanner.freeToUse "L'utilizzo di Tor è gratuito grazie alle donazioni fatte da persone come te.">
<!ENTITY aboutTor.donationBanner.buttonA "Dona Adesso">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "VIA\nDAI\nMEI\nDATI">
-<!ENTITY aboutTor.yec.motto "La privacy è un diritto umano">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "La tua donazione sarà abbinata a "Amici di Tor", fino a $ 150.000.">
diff --git a/chrome/locale/ja/aboutTor.dtd b/chrome/locale/ja/aboutTor.dtd
index 7a7d2dc9..10eb73a1 100644
--- a/chrome/locale/ja/aboutTor.dtd
+++ b/chrome/locale/ja/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Tor ニュースに申し込む。">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor は皆さんからの寄付に支えられています。">
<!ENTITY aboutTor.donationBanner.buttonA "今すぐ寄付">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "データ\nに\n手を\n触れるな">
-<!ENTITY aboutTor.yec.motto "プライバシーは人権です">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "あなたが寄付した額と同額を、Torのパートナーも寄付します (最大150,000ドル)">
diff --git a/chrome/locale/ja/torbutton.dtd b/chrome/locale/ja/torbutton.dtd
index fcc97264..0c0f78c0 100644
--- a/chrome/locale/ja/torbutton.dtd
+++ b/chrome/locale/ja/torbutton.dtd
@@ -1,5 +1,5 @@
<!ENTITY torbutton.context_menu.new_identity "新しい識別子">
-<!ENTITY torbutton.context_menu.new_identity_sentence_case "New identity">
+<!ENTITY torbutton.context_menu.new_identity_sentence_case "新しい識別子">
<!ENTITY torbutton.context_menu.new_identity_key "I">
<!ENTITY torbutton.context_menu.new_circuit "このサイト用の Tor 回線を再構築">
<!ENTITY torbutton.context_menu.new_circuit_sentence_case "New tor circuit for this site">
@@ -47,7 +47,7 @@
<!ENTITY torbutton.prefs.sec_custom_summary "あなたのブラウザーにおけるカスタム設定はセキュリティ結果に影響を及ぼしません。セキュリティとプライバシーに関してはデフォルトのセキュリティレベルのひとつを選択することをおすすめいたします。">
<!ENTITY torbutton.prefs.sec_restore_defaults "デフォルトにもどす">
<!ENTITY torbutton.prefs.sec_advanced_security_settings "詳細セキュリティ設定…">
-<!ENTITY torbutton.prefs.sec_change "Change…">
+<!ENTITY torbutton.prefs.sec_change "変更…">
<!ENTITY torbutton.circuit_display.title "Tor 回線">
<!ENTITY torbutton.circuit_display.new_circuit "このサイト用の回線を再構築">
diff --git a/chrome/locale/ka/aboutTor.dtd b/chrome/locale/ka/aboutTor.dtd
index 14c2db32..1f1b89bf 100644
--- a/chrome/locale/ka/aboutTor.dtd
+++ b/chrome/locale/ka/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "გამოიწერეთ Tor-ის სიახლეები.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor უფასოა, თქვენნაირი ადამიანების შემოწირულობების წყალობით.">
<!ENTITY aboutTor.donationBanner.buttonA "გაიღეთ თანხა">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "ᲮᲔᲚᲔᲑᲘ\nᲨᲝᲠᲡ ᲩᲔᲛᲘ\nᲞᲘᲠᲐᲓᲘ\nᲡᲘᲕᲠᲪᲘᲓᲐᲜ">
-<!ENTITY aboutTor.yec.motto "პირადულობა ადამიანის ძირეული უფლებაა">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "თქვენი შემოწირულობა გაორმაგდება Tor-ის მეგობრების მიერ, $150,000-ამდე.">
diff --git a/chrome/locale/ko/aboutTor.dtd b/chrome/locale/ko/aboutTor.dtd
index 18bf3bfe..04e6de97 100644
--- a/chrome/locale/ko/aboutTor.dtd
+++ b/chrome/locale/ko/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Tor 뉴스를 구독.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor는 바로 당신과 같은 사람들의 기부 덕분에 자유롭게 사용할 수 있습니다.">
<!ENTITY aboutTor.donationBanner.buttonA "기부하기">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "HANDS\nOFF\nMY\nDATA">
-<!ENTITY aboutTor.yec.motto "프라이버시는 인권입니다">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Your donation will be matched by Friends of Tor, up to $150,000.">
diff --git a/chrome/locale/lt/aboutTor.dtd b/chrome/locale/lt/aboutTor.dtd
index 7885a6be..4b711723 100644
--- a/chrome/locale/lt/aboutTor.dtd
+++ b/chrome/locale/lt/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Užsisakykite Tor naujienas.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor yra nemokamas naudoti dėl paaukojimų iš tokių žmonių kaip jūs.">
<!ENTITY aboutTor.donationBanner.buttonA "Paaukokite dabar">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "PATRAUKITE\nRANKAS\nNUO\nMANO\nDUOMENŲ">
-<!ENTITY aboutTor.yec.motto "Privatumas yra žmogaus teisė">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "„Friends of Tor“ paaukos tiek pat, kiek ir jūs, iki $150000.">
diff --git a/chrome/locale/lt/torbutton.dtd b/chrome/locale/lt/torbutton.dtd
index 3e1e58e1..37326068 100644
--- a/chrome/locale/lt/torbutton.dtd
+++ b/chrome/locale/lt/torbutton.dtd
@@ -1,8 +1,8 @@
<!ENTITY torbutton.context_menu.new_identity "Nauja tapatybė">
-<!ENTITY torbutton.context_menu.new_identity_sentence_case "New identity">
+<!ENTITY torbutton.context_menu.new_identity_sentence_case "Nauja tapatybė">
<!ENTITY torbutton.context_menu.new_identity_key "T">
<!ENTITY torbutton.context_menu.new_circuit "Nauja Tor grandinė šiai svetainei">
-<!ENTITY torbutton.context_menu.new_circuit_sentence_case "New tor circuit for this site">
+<!ENTITY torbutton.context_menu.new_circuit_sentence_case "Nauja Tor grandinė šiai svetainei">
<!ENTITY torbutton.context_menu.new_circuit_key "G">
<!ENTITY torbutton.context_menu.networksettings "Tor tinklo nustatymai…">
<!ENTITY torbutton.context_menu.networksettings.key "N">
diff --git a/chrome/locale/mk/aboutTor.dtd b/chrome/locale/mk/aboutTor.dtd
index 785c23f3..5853c075 100644
--- a/chrome/locale/mk/aboutTor.dtd
+++ b/chrome/locale/mk/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Пријавете се за Tor Вести.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor е бесплатен за користење благодарение на донациите од луѓе како вас.">
<!ENTITY aboutTor.donationBanner.buttonA "Донирај сега">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "РАЦЕТЕ\nПОНАСТРАНА\nОД\nМОИТЕ\nПОДАТОЦИ">
-<!ENTITY aboutTor.yec.motto "Приватноста е човеково право">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Вашата донација ќе биде дуплицирана од Пријателите на Tor, до $150,000.">
diff --git a/chrome/locale/mk/torbutton.dtd b/chrome/locale/mk/torbutton.dtd
index 35bc81b3..d8f0c6a8 100644
--- a/chrome/locale/mk/torbutton.dtd
+++ b/chrome/locale/mk/torbutton.dtd
@@ -1,8 +1,8 @@
<!ENTITY torbutton.context_menu.new_identity "Нов идентитет">
-<!ENTITY torbutton.context_menu.new_identity_sentence_case "New identity">
+<!ENTITY torbutton.context_menu.new_identity_sentence_case "Нов идентитет">
<!ENTITY torbutton.context_menu.new_identity_key "I">
<!ENTITY torbutton.context_menu.new_circuit "Нов Tor круг за оваа страна">
-<!ENTITY torbutton.context_menu.new_circuit_sentence_case "New tor circuit for this site">
+<!ENTITY torbutton.context_menu.new_circuit_sentence_case "Нов Tor круг за оваа веб страна">
<!ENTITY torbutton.context_menu.new_circuit_key "C">
<!ENTITY torbutton.context_menu.networksettings "Тор мрежни поставки...">
<!ENTITY torbutton.context_menu.networksettings.key "N">
diff --git a/chrome/locale/ms/aboutTor.dtd b/chrome/locale/ms/aboutTor.dtd
index 231e59a1..b49406f7 100644
--- a/chrome/locale/ms/aboutTor.dtd
+++ b/chrome/locale/ms/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Daftar untuk dapatkan Berita Tor.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor sepenuhnya percuma digunakan kerana adanya derma oleh individu seperti anda.">
<!ENTITY aboutTor.donationBanner.buttonA "Dermalah Sekarang">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "HANDS\nOFF\nMY\nDATA">
-<!ENTITY aboutTor.yec.motto "Privasi atau kesendirian ialah hak asasi manusia">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Your donation will be matched by Friends of Tor, up to $150,000.">
diff --git a/chrome/locale/my/aboutTor.dtd b/chrome/locale/my/aboutTor.dtd
index d4be1cf6..06bc3410 100644
--- a/chrome/locale/my/aboutTor.dtd
+++ b/chrome/locale/my/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Tor News သတင်းများအတွက် အမည် စာရင်းသွင်းလိုက်ပါ။">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor သည် သင့်လို သုံးသူများမှ လှူဒါန်းငွေကြောင့် အခမဲ့သုံးနိုင်ပါသည်။">
<!ENTITY aboutTor.donationBanner.buttonA "အခုဘဲ လှူမယ်">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "HANDS\nOFF\nMY\nDATA">
-<!ENTITY aboutTor.yec.motto "Privacy is a human right">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Your donation will be matched by Friends of Tor, up to $150,000.">
diff --git a/chrome/locale/nb-NO/aboutTor.dtd b/chrome/locale/nb-NO/aboutTor.dtd
index fb6544bf..15c0c327 100644
--- a/chrome/locale/nb-NO/aboutTor.dtd
+++ b/chrome/locale/nb-NO/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Registrer deg for Tor-nyheter.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor er gratis å bruke, grunnet bidrag fra folk som deg.">
<!ENTITY aboutTor.donationBanner.buttonA "Donér nå">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "HANDS\nOFF\nMY\nDATA">
-<!ENTITY aboutTor.yec.motto "Personvern er en menneskerettighet">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Your donation will be matched by Friends of Tor, up to $150,000.">
diff --git a/chrome/locale/nl/aboutTor.dtd b/chrome/locale/nl/aboutTor.dtd
index 9af03022..ca46073b 100644
--- a/chrome/locale/nl/aboutTor.dtd
+++ b/chrome/locale/nl/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Meld u aan voor de Tor-nieuwsbrief.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor is gratis te gebruiken dankzij donaties van mensen zoals u.">
<!ENTITY aboutTor.donationBanner.buttonA "Doneer nu">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "HANDS\nOFF\nMY\nDATA">
-<!ENTITY aboutTor.yec.motto "Privacy is een mensenrecht">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Uw donatie wordt verdubbeld door Friends of Tor, tot een maximum van $150.000.">
diff --git a/chrome/locale/nl/torbutton.dtd b/chrome/locale/nl/torbutton.dtd
index 5efd0182..9d64c1d1 100644
--- a/chrome/locale/nl/torbutton.dtd
+++ b/chrome/locale/nl/torbutton.dtd
@@ -2,7 +2,7 @@
<!ENTITY torbutton.context_menu.new_identity_sentence_case "Nieuwe identiteit">
<!ENTITY torbutton.context_menu.new_identity_key "d">
<!ENTITY torbutton.context_menu.new_circuit "Nieuw Tor-circuit voor deze website">
-<!ENTITY torbutton.context_menu.new_circuit_sentence_case "New tor circuit for this site">
+<!ENTITY torbutton.context_menu.new_circuit_sentence_case "Nieuw Torcircuit voor deze website">
<!ENTITY torbutton.context_menu.new_circuit_key "c">
<!ENTITY torbutton.context_menu.networksettings "Tor-netwerkinstellingen…">
<!ENTITY torbutton.context_menu.networksettings.key "n">
@@ -47,7 +47,7 @@
<!ENTITY torbutton.prefs.sec_custom_summary "Uw aangepaste browservoorkeuren hebben tot ongebruikelijke beveiligingsinstellingen geleid. Uit veiligheids- en privacyoverwegingen raden we aan een van de standaard beveiligingsniveaus te kiezen.">
<!ENTITY torbutton.prefs.sec_restore_defaults "Standaardwaarden herstellen">
<!ENTITY torbutton.prefs.sec_advanced_security_settings "Geavanceerde beveiligingsinstellingen…">
-<!ENTITY torbutton.prefs.sec_change "Change…">
+<!ENTITY torbutton.prefs.sec_change "Wijzigen …">
<!ENTITY torbutton.circuit_display.title "Tor-circuit">
<!ENTITY torbutton.circuit_display.new_circuit "Nieuw circuit voor deze website">
diff --git a/chrome/locale/pl/aboutTor.dtd b/chrome/locale/pl/aboutTor.dtd
index 6750b260..f67d40b9 100644
--- a/chrome/locale/pl/aboutTor.dtd
+++ b/chrome/locale/pl/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Zapisz się na newsletter.">
<!ENTITY aboutTor.donationBanner.freeToUse "Z przeglądarki Tor można korzystać bezpłatnie dzięki darowiznom od osób takich jak Ty.">
<!ENTITY aboutTor.donationBanner.buttonA "Wesprzyj teraz">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "RĘCE\nPRECZ\nOD\nMOICH\nDANYCH">
-<!ENTITY aboutTor.yec.motto "Prawo do prywatności jest prawem człowieka. ">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Twoja darowizna zostanie wyrównana przez przyjaciół sieci Tor, aż do 150 000 dolarów.">
diff --git a/chrome/locale/pt-BR/aboutTor.dtd b/chrome/locale/pt-BR/aboutTor.dtd
index 71aa2346..10cc06e9 100644
--- a/chrome/locale/pt-BR/aboutTor.dtd
+++ b/chrome/locale/pt-BR/aboutTor.dtd
@@ -30,31 +30,3 @@
<!ENTITY aboutTor.newsletter.link_text "Inscreva-se para receber Notícias do Tor.">
<!ENTITY aboutTor.donationBanner.freeToUse "O Tor é gratuito graças às doações de pessoas como você.">
<!ENTITY aboutTor.donationBanner.buttonA "Doe Agora">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "TIREM AS\nMÃOS\nDOS MEUS\nDADOS">
-<!ENTITY aboutTor.yec.motto "Privacidade é um direito humano.">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Os Amigos do Tor farão uma doação do mesmo valor da sua, no limite de $150,000.00.">
diff --git a/chrome/locale/ro/aboutTor.dtd b/chrome/locale/ro/aboutTor.dtd
index 9c5d3c33..07488af9 100644
--- a/chrome/locale/ro/aboutTor.dtd
+++ b/chrome/locale/ro/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Abonează-te la Tor News.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor poate fi folosit gratuit datorită donațiilor de la oameni ca tine.">
<!ENTITY aboutTor.donationBanner.buttonA "Donează Acum">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "IA-ȚI\nMÂINILE\nDE PE DATELE\nMELE">
-<!ENTITY aboutTor.yec.motto "Confidențialitatea este un drept uman">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Donația dumneavoastră va fi potrivită de Prietenii lui Tor, până la 150.000 USD.">
diff --git a/chrome/locale/ru/aboutTor.dtd b/chrome/locale/ru/aboutTor.dtd
index 7ea0b5f8..372bbcd5 100644
--- a/chrome/locale/ru/aboutTor.dtd
+++ b/chrome/locale/ru/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Подпишитесь на новости Tor.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor бесплатен благодаря пожертвованиям таких людей, как вы.">
<!ENTITY aboutTor.donationBanner.buttonA "Пожертвовать">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "РУКИ\nПРОЧЬ\nОТ МОИХ\nДАННЫХ">
-<!ENTITY aboutTor.yec.motto "Приватность – право человека">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Ваше пожертвование (до $150000) будет удвоено Friends of Tor.">
diff --git a/chrome/locale/sv-SE/aboutTor.dtd b/chrome/locale/sv-SE/aboutTor.dtd
index f5e56647..4ff532ec 100644
--- a/chrome/locale/sv-SE/aboutTor.dtd
+++ b/chrome/locale/sv-SE/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Anmäl dig till Tor-nyheter.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor är gratis att använda på grund av donationer från personer som du.">
<!ENTITY aboutTor.donationBanner.buttonA "Donera nu">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "HÄNDERNA\nBORT FRÅN\nMINA\nDATA">
-<!ENTITY aboutTor.yec.motto "Integritet är en mänsklig rättighet">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Din donation kommer att matchas av Friends of Tor, upp till $150 000.">
diff --git a/chrome/locale/th/aboutTor.dtd b/chrome/locale/th/aboutTor.dtd
index 29531f5d..96ebca5e 100644
--- a/chrome/locale/th/aboutTor.dtd
+++ b/chrome/locale/th/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "สมัครรับข่าวสารเกี่ยวกับ Tor">
<!ENTITY aboutTor.donationBanner.freeToUse "บริการ Tor นี้ฟรี ไม่มีค่าใช้จ่ายใดๆเพราะเงินบริจาคจากผู้มีน้ำใจอย่างคุณ">
<!ENTITY aboutTor.donationBanner.buttonA "ร่วมบริจาค">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "HANDS\nOFF\nMY\nDATA">
-<!ENTITY aboutTor.yec.motto "ความเป็นส่วนตัวคือสิทธิมนุษยชน">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "เงินบริจาคของคุณจะส่งมอบให้ Tor สูงสุดถึง 150,000 ดอลลาร์สหรัฐ">
diff --git a/chrome/locale/tr/aboutTor.dtd b/chrome/locale/tr/aboutTor.dtd
index dc3eb89e..5c330e18 100644
--- a/chrome/locale/tr/aboutTor.dtd
+++ b/chrome/locale/tr/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Tor duyurularına abone olun">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor sizin gibi insanların bağışları ile desteklendiği için ücretsiz olarak kullanılabiliyor.">
<!ENTITY aboutTor.donationBanner.buttonA "Bağış yapın">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "VERİLERİME\nDOKUNMA">
-<!ENTITY aboutTor.yec.motto "Kişisel gizlilik bir insan hakkıdır">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Friends of Tor, $150.000 altında yaptığınız bağış kadar katkıda bulunacak.">
diff --git a/chrome/locale/vi/aboutTor.dtd b/chrome/locale/vi/aboutTor.dtd
index 45d44a81..b6bf4286 100644
--- a/chrome/locale/vi/aboutTor.dtd
+++ b/chrome/locale/vi/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "Đăng kí nhận tin tức từ Tor.">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor miễn phí là nhờ sự ủng hộ của những người như bạn.">
<!ENTITY aboutTor.donationBanner.buttonA "Đóng góp Ngay bây giờ">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "HANDS\nOFF\nMY\nDATA">
-<!ENTITY aboutTor.yec.motto "Privacy is a human right">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Your donation will be matched by Friends of Tor, up to $150,000.">
diff --git a/chrome/locale/zh-CN/aboutTor.dtd b/chrome/locale/zh-CN/aboutTor.dtd
index 4aa0815c..5b4f5fa7 100644
--- a/chrome/locale/zh-CN/aboutTor.dtd
+++ b/chrome/locale/zh-CN/aboutTor.dtd
@@ -29,31 +29,3 @@
<!ENTITY aboutTor.newsletter.link_text "订阅 Tor 的最新动态">
<!ENTITY aboutTor.donationBanner.freeToUse "Tor 是免费使用的,因为有和您一样的人捐助。">
<!ENTITY aboutTor.donationBanner.buttonA "立即捐助">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "别碰\n我的\n隐私">
-<!ENTITY aboutTor.yec.motto "隐私是一项人权">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "您的捐款将由 Tor 的伙伴们配捐,最高15万美元。">
diff --git a/chrome/locale/zh-CN/torbutton.dtd b/chrome/locale/zh-CN/torbutton.dtd
index d6d1a237..221c89e4 100644
--- a/chrome/locale/zh-CN/torbutton.dtd
+++ b/chrome/locale/zh-CN/torbutton.dtd
@@ -2,7 +2,7 @@
<!ENTITY torbutton.context_menu.new_identity_sentence_case "新建身份">
<!ENTITY torbutton.context_menu.new_identity_key "I">
<!ENTITY torbutton.context_menu.new_circuit "为此站点使用新的 Tor 链路">
-<!ENTITY torbutton.context_menu.new_circuit_sentence_case "New tor circuit for this site">
+<!ENTITY torbutton.context_menu.new_circuit_sentence_case "为此站点建立新的 Tor 链路">
<!ENTITY torbutton.context_menu.new_circuit_key "C">
<!ENTITY torbutton.context_menu.networksettings "Tor 网络设置…">
<!ENTITY torbutton.context_menu.networksettings.key "N">
@@ -47,7 +47,7 @@
<!ENTITY torbutton.prefs.sec_custom_summary "您自定义的浏览器设置导致了不安全的安全设置。出于安全和隐私考虑,我们建议您选择一个默认的安全级别。">
<!ENTITY torbutton.prefs.sec_restore_defaults "恢复默认设置">
<!ENTITY torbutton.prefs.sec_advanced_security_settings "高级安全选项…">
-<!ENTITY torbutton.prefs.sec_change "Change…">
+<!ENTITY torbutton.prefs.sec_change "更改…">
<!ENTITY torbutton.circuit_display.title "Tor 链路">
<!ENTITY torbutton.circuit_display.new_circuit "为此站点使用新线路">
diff --git a/chrome/locale/zh-TW/aboutTor.dtd b/chrome/locale/zh-TW/aboutTor.dtd
index 5dc4ac80..ead0eb2a 100644
--- a/chrome/locale/zh-TW/aboutTor.dtd
+++ b/chrome/locale/zh-TW/aboutTor.dtd
@@ -27,33 +27,5 @@
<!ENTITY aboutTor.newsletter.tagline "將 Tor 的最新消息直接傳送到您的收件匣。">
<!ENTITY aboutTor.newsletter.link_text "訂閱 Tor 的新資訊。">
-<!ENTITY aboutTor.donationBanner.freeToUse "由於有像您這樣的人捐款,Tor 可以免費使用。">
+<!ENTITY aboutTor.donationBanner.freeToUse "由於有像您這樣的人捐款,洋蔥路由才得以免費使用。">
<!ENTITY aboutTor.donationBanner.buttonA "立刻捐款">
-
-<!-- Year end campaign strings -->
-
-<!-- LOCALIZATION NOTE (aboutTor.yec.slogan): This string is written on a protest sign and the translated
- phrase needs to be a short and concise slogan. We would like the phrase to fit on 3 to 5 lines. If a
- translation of 'HANDS OFF MY DATA' cannot be made short, we have provided these alternative slogans
- with a similar theme:
-
- - DON'T TOUCH MY DATA
- - DON'T SPY ON MY DATA
- - MY DATA IS PRIVATE
- - KEEP OFF MY DATA
-
- Please place newline characters (\n) between words or phrases which can be placed in separate lines
- so we can word-wrap our final assets correctly.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.slogan "別\n碰\n我的\n資料">
-<!ENTITY aboutTor.yec.motto "隱私即人權">
-<!-- LOCALIZATION NOTE (aboutTor.yec.donationMatch): Please translate the 'Friends of Tor' phrase, but
- also format it like the name of an organization in whichever way that is appropriate for your locale.
-
- Please keep the currency in USD.
-
- Thank you!
--->
-<!ENTITY aboutTor.yec.donationMatch "Friends of Tor 組織將會捐助與您所捐助的款項相同的金額,上限為$150,000。">
diff --git a/chrome/locale/zh-TW/torbutton.properties b/chrome/locale/zh-TW/torbutton.properties
index fecce63a..586a922a 100644
--- a/chrome/locale/zh-TW/torbutton.properties
+++ b/chrome/locale/zh-TW/torbutton.properties
@@ -78,7 +78,7 @@ onionServices.descInvalid.longDescription=技術細節: %S — 該洋蔥服務
# Tor SOCKS error 0xF2:
onionServices.introFailed.pageTitle=載入洋蔥站台時發生問題
onionServices.introFailed.header=洋蔥站台已斷線
-onionServices.introFailed=最可能的原因是 Onion 網站已離線。請聯絡 Onion 網站管理員。
+onionServices.introFailed=最有可能的原因是該洋蔥站台已離線,請聯絡該站台的管理員。
onionServices.introFailed.longDescription=技術細節: %S — 該洋蔥服務之識別證已找到,但該服務與引見節點之連線已中斷,造成引見連線建立失敗。這通常是肇因於該服務更換識別證,或是已經不再提供服務。
# Tor SOCKS error 0xF3:
onionServices.rendezvousFailed.pageTitle=載入洋蔥站台發生問題
1
0
[torbutton/master] Bug 40679: Missing features on first-time launch in esr91
by gk@torproject.org 19 Jan '22
by gk@torproject.org 19 Jan '22
19 Jan '22
commit 10ecf6dd6ecf4ddf8f4cacfdfcb36be0881e83bb
Author: Richard Pospesel <richard(a)torproject.org>
Date: Thu Dec 16 14:38:05 2021 +0100
Bug 40679: Missing features on first-time launch in esr91
- fixes myriad problems with our async control port communication
logic
- fixes tor-browser#40679
---
chrome/content/tor-circuit-display.js | 21 +-
chrome/content/torbutton.js | 4 +-
modules/tor-control-port.js | 573 +++++++++++++++++++++-------------
3 files changed, 361 insertions(+), 237 deletions(-)
diff --git a/chrome/content/tor-circuit-display.js b/chrome/content/tor-circuit-display.js
index 4e0088f0..d6034384 100644
--- a/chrome/content/tor-circuit-display.js
+++ b/chrome/content/tor-circuit-display.js
@@ -29,7 +29,7 @@ let createTorCircuitDisplay = (function () {
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
// Import the controller code.
-let { controller } = ChromeUtils.import("resource://torbutton/modules/tor-control-port.js", {});
+let { wait_for_controller } = ChromeUtils.import("resource://torbutton/modules/tor-control-port.js", {});
// Utility functions
let { bindPrefAndInit, observe, getLocale, getDomainForBrowser, torbutton_get_property_string } = ChromeUtils.import("resource://torbutton/modules/utils.js", {});
@@ -458,7 +458,7 @@ let setupDisplay = function (enablePrefName) {
syncDisplayWithSelectedTab(false);
if (myController) {
if (stopCollectingIsolationData) {
- stopCollectingIsolationData();
+ stopCollectingIsolationData();
}
if (stopCollectingBrowserCredentials) {
stopCollectingBrowserCredentials();
@@ -469,19 +469,20 @@ let setupDisplay = function (enablePrefName) {
myController = null;
}
},
- start = function () {
+ start = async function () {
if (!myController) {
- myController = controller(function (err) {
- // An error has occurred.
+ try {
+ myController = await wait_for_controller();
+ syncDisplayWithSelectedTab(true);
+ stopCollectingIsolationData = collectIsolationData(myController, updateCircuitDisplay);
+ stopCollectingBrowserCredentials = collectBrowserCredentials();
+ stopEnsuringCorrectPopupDimensions = ensureCorrectPopupDimensions();
+ } catch (err) {
logger.eclog(5, err);
logger.eclog(5, "Disabling tor display circuit because of an error.");
myController.close();
stop();
- });
- syncDisplayWithSelectedTab(true);
- stopCollectingIsolationData = collectIsolationData(myController, updateCircuitDisplay);
- stopCollectingBrowserCredentials = collectBrowserCredentials();
- stopEnsuringCorrectPopupDimensions = ensureCorrectPopupDimensions();
+ }
}
};
try {
diff --git a/chrome/content/torbutton.js b/chrome/content/torbutton.js
index 65048b1a..3bfaa1f8 100644
--- a/chrome/content/torbutton.js
+++ b/chrome/content/torbutton.js
@@ -28,7 +28,7 @@ let {
torbutton_log,
torbutton_get_property_string,
} = ChromeUtils.import("resource://torbutton/modules/utils.js", {});
-let { configureControlPortModule, controller } = Cu.import("resource://torbutton/modules/tor-control-port.js", {});
+let { configureControlPortModule, wait_for_controller } = Cu.import("resource://torbutton/modules/tor-control-port.js", {});
const k_tb_tor_check_failed_topic = "Torbutton:TorCheckFailed";
@@ -352,7 +352,7 @@ async function torbutton_send_ctrl_cmd(command) {
let response = null;
try {
const avoidCache = true;
- let torController = controller(e => { throw e; }, avoidCache);
+ let torController = await wait_for_controller(avoidCache);
let bytes = await torController.sendCommand(command);
if (!bytes.startsWith("250")) {
diff --git a/modules/tor-control-port.js b/modules/tor-control-port.js
index ef7bbe69..51ac8ac0 100644
--- a/modules/tor-control-port.js
+++ b/modules/tor-control-port.js
@@ -7,16 +7,16 @@
//
// To import the module, use
//
-// let { configureControlPortModule, controller } =
+// let { configureControlPortModule, controller, wait_for_controller } =
// Components.utils.import("path/to/tor-control-port.js", {});
//
-// See the second-to-last function defined in this file:
+// See the third-to-last function defined in this file:
// configureControlPortModule(ipcFile, host, port, password)
// for usage of the configureControlPortModule function.
//
-// See the last function defined in this file:
-// controller(onError)
-// for usage of the controller function.
+// See the last functions defined in this file:
+// controller(avoidCache), wait_for_controller(avoidCache)
+// for usage of the controller functions.
/* jshint esnext: true */
/* jshint -W097 */
@@ -29,6 +29,14 @@ let { Constructor: CC } = Components;
// ### Import Mozilla Services
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+const { TorProtocolService, TorProcessStatus } = ChromeUtils.import(
+ "resource:///modules/TorProtocolService.jsm"
+);
+// tor-launcher observer topics
+const TorTopics = Object.freeze({
+ ProcessIsReady: "TorProcessIsReady",
+});
+
// __log__.
// Logging function
let logger = Cc["@torproject.org/torbutton-logger;1"]
@@ -38,159 +46,289 @@ let log = x => logger.eclog(3, x.trimRight().replace(/\r\n/g, "\n"));
// ### announce this file
log("Loading tor-control-port.js\n");
-// ## io
-// I/O utilities namespace
-let io = {};
+class AsyncSocket {
+ constructor(ipcFile, host, port) {
+ let sts = Cc["@mozilla.org/network/socket-transport-service;1"].getService(Ci.nsISocketTransportService);
+ const OPEN_UNBUFFERED = Ci.nsITransport.OPEN_UNBUFFERED;
-// __io.asyncSocketStreams(ipcFile, host, port)__.
-// Creates a pair of asynchronous input and output streams for a socket at the
-// given ipcFile or host and port.
-io.asyncSocketStreams = function (ipcFile, host, port) {
- let sts = Cc["@mozilla.org/network/socket-transport-service;1"]
- .getService(Ci.nsISocketTransportService),
- UNBUFFERED = Ci.nsITransport.OPEN_UNBUFFERED;
-
- // Create an instance of a socket transport.
- let socketTransport;
- if (ipcFile) {
- socketTransport = sts.createUnixDomainTransport(ipcFile);
- } else {
- socketTransport = sts.createTransport([], host, port, null, null);
+ let socketTransport = ipcFile ?
+ sts.createUnixDomainTransport(ipcFile) :
+ sts.createTransport([], host, port, null, null);
+
+
+ this.outputStream = socketTransport.openOutputStream(OPEN_UNBUFFERED, 1, 1).QueryInterface(Ci.nsIAsyncOutputStream);
+ this.outputQueue = [];
+
+ this.inputStream = socketTransport.openInputStream(OPEN_UNBUFFERED, 1, 1).QueryInterface(Ci.nsIAsyncInputStream);
+ this.scriptableInputStream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream);
+ this.scriptableInputStream.init(this.inputStream);
+ this.inputQueue = [];
}
- // Open unbuffered asynchronous outputStream.
- let outputStream = socketTransport.openOutputStream(UNBUFFERED, 1, 1)
- .QueryInterface(Ci.nsIAsyncOutputStream),
- // Open unbuffered asynchronous inputStream.
- inputStream = socketTransport.openInputStream(UNBUFFERED, 1, 1)
- .QueryInterface(Ci.nsIAsyncInputStream);
- return [inputStream, outputStream];
-};
+ // asynchronously write string to underlying socket and return number of bytes written
+ async write(str) {
+ return new Promise((resolve, reject) => {
-// __io.pumpInputStream(scriptableInputStream, onInputData, onError)__.
-// Take an input stream and asynchronously pass data to the onInputData callback.
-io.pumpInputStream = function (inputStream, onInputData, onError) {
- // Wrap raw inputStream with a "ScriptableInputStream" so we can read incoming data.
- let ScriptableInputStream = Components.Constructor(
- "@mozilla.org/scriptableinputstream;1", "nsIScriptableInputStream", "init"),
- scriptableInputStream = new ScriptableInputStream(inputStream),
- awaitNextChunk = function () {
- inputStream.asyncWait({
- onInputStreamReady: (stream) => {
- try {
- let chunk = scriptableInputStream.read(scriptableInputStream.available());
- onInputData(chunk);
- awaitNextChunk();
- } catch (err) {
- if (err.result !== Cr.NS_BASE_STREAM_CLOSED) {
- onError(err);
- }
- }
+ // asyncWait next write request
+ const tryAsyncWait = () => {
+ if (this.outputQueue.length > 0) {
+ this.outputStream.asyncWait(
+ this.outputQueue.at(0), // next request
+ 0, 0, Services.tm.currentThread);
+ }
+ };
+
+ // output stream can only have 1 registered callback at a time, so multiple writes
+ // need to be queued up (see nsIAsyncOutputStream.idl)
+ this.outputQueue.push({
+ // Implement an nsIOutputStreamCallback:
+ onOutputStreamReady: () => {
+ try {
+ let bytesWritten = this.outputStream.write(str, str.length);
+
+ // remove this callback object from queue as it is now completed
+ this.outputQueue.shift();
+
+ // request next wait if there is one
+ tryAsyncWait();
+
+ // finally resolve promise
+ resolve(bytesWritten);
+ } catch (err) {
+ // reject promise on error
+ reject(err);
}
- }, 0, 0, Services.tm.currentThread);
+ }
+ });
+
+ // length 1 imples that there is no in-flight asyncWait, so we may immediately
+ // follow through on this write
+ if (this.outputQueue.length == 1) {
+ tryAsyncWait();
+ }
+ });
+ }
+
+ // asynchronously read string from underlying socket and return it
+ async read() {
+ return new Promise((resolve, reject) => {
+
+ const tryAsyncWait = () => {
+ if (this.inputQueue.length > 0) {
+ this.inputStream.asyncWait(
+ this.inputQueue.at(0), // next input request
+ 0, 0, Services.tm.currentThread);
+ }
};
- awaitNextChunk();
-};
-// __io.asyncSocket(ipcFile, host, port, onInputData, onError)__.
-// Creates an asynchronous, text-oriented IPC socket (if ipcFile is defined)
-// or a TCP socket at host:port.
-// The onInputData callback should accept a single argument, which will be called
-// repeatedly, whenever incoming text arrives. Returns a socket object with two methods:
-// socket.write(text) and socket.close(). onError will be passed the error object
-// whenever a write fails.
-io.asyncSocket = function (ipcFile, host, port, onInputData, onError) {
- let [inputStream, outputStream] = io.asyncSocketStreams(ipcFile, host, port),
- pendingWrites = [];
- // Run an input stream pump to send incoming data to the onInputData callback.
- io.pumpInputStream(inputStream, onInputData, onError);
- // Return the "socket object" as described.
- return {
- // Write a message to the socket.
- write : function(aString) {
- pendingWrites.push(aString);
- outputStream.asyncWait(
- // Implement an nsIOutputStreamCallback:
- { onOutputStreamReady : function () {
- let totalString = pendingWrites.join("");
- try {
- outputStream.write(totalString, totalString.length);
- log("controlPort << " + totalString);
- } catch (err) {
- onError(err);
- }
- pendingWrites = [];
- } },
- 0, 0, Services.tm.currentThread);
- },
- // Close the socket.
- close : function () {
- // Close stream objects.
- inputStream.close();
- outputStream.close();
- }
- };
-};
+ this.inputQueue.push({
+ onInputStreamReady: (stream) => {
+ try {
+ // read our string from input stream
+ let str = this.scriptableInputStream.read(this.scriptableInputStream.available());
-// __io.onDataFromOnLine(onLine)__.
-// Converts a callback that expects incoming individual lines of text to a callback that
-// expects incoming raw socket string data.
-io.onDataFromOnLine = function (onLine) {
- // A private variable that stores the last unfinished line.
- let pendingData = "";
- // Return a callback to be passed to io.asyncSocket. First, splits data into lines of
- // text. If the incoming data is not terminated by CRLF, then the last
- // unfinished line will be stored in pendingData, to be prepended to the data in the
- // next call to onData. The already complete lines of text are then passed in sequence
- // to onLine.
- return function (data) {
- let totalData = pendingData + data,
- lines = totalData.split("\r\n"),
- n = lines.length;
- pendingData = lines[n - 1];
- // Call onLine for all completed lines.
- lines.slice(0,-1).map(onLine);
- };
+ // remove this callback object from queue now that we have read
+ this.inputQueue.shift();
+
+ // request next wait if there is one
+ tryAsyncWait();
+
+ // finally resolve promise
+ resolve(str);
+ } catch (err) {
+ reject(err);
+ }
+ }
+ });
+
+ // length 1 imples that there is no in-flight asyncWait, so we may immediately
+ // follow through on this read
+ if (this.inputQueue.length == 1) {
+ tryAsyncWait();
+ }
+ });
+ }
+
+ close() {
+ this.outputStream.close();
+ this.inputStream.close();
+ }
};
-// __io.onLineFromOnMessage(onMessage)__.
-// Converts a callback that expects incoming control port multiline message strings to a
-// callback that expects individual lines.
-io.onLineFromOnMessage = function (onMessage) {
- // A private variable that stores the last unfinished line.
- let pendingLines = [],
- // A private variable to monitor whether we are receiving a multiline
- // value, beginning with ###+ and ending with a single ".".
- multilineValueInProgress = false;
- // Return a callback that expects individual lines.
- return function (line) {
- // Add to the list of pending lines.
- pendingLines.push(line);
- // 'Multiline values' are possible. We avoid interrupting one by detecting it
- // and waiting for a terminating "." on its own line.
- // (See control-spec section 3.9 and https://trac.torproject.org/16990#comment:28
- if (line.match(/^\d\d\d\+.+?=$/) && pendingLines.length === 1) {
- multilineValueInProgress = true;
+class ControlSocket {
+ constructor(asyncSocket) {
+ this.socket = asyncSocket;
+ this._isOpen = true;
+ this.pendingData = "";
+ this.pendingLines = [];
+
+ this.mainDispatcher = io.callbackDispatcher();
+ this.notificationDispatcher = io.callbackDispatcher();
+ // mainDispatcher pushes only async notifications (650) to notificationDispatcher
+ this.mainDispatcher.addCallback(/^650/, this._handleNotification.bind(this));
+ // callback for handling responses and errors
+ this.mainDispatcher.addCallback(/^[245]\d\d/, this._handleCommandReply.bind(this) );
+
+ this.commandQueue = [];
+
+ this._startMessagePump();
+ }
+
+ // blocks until an entire line is read and returns it
+ // immediately returns next line in queue (pendingLines) if present
+ async _readLine() {
+ // keep reading from socket until we have a full line to return
+ while(this.pendingLines.length == 0) {
+ // read data from our socket and spit on newline tokens
+ this.pendingData += await this.socket.read();
+ let lines = this.pendingData.split("\r\n");
+
+ // the last line will either be empty string, or a partial read of a response/event
+ // so save it off for the next socket read
+ this.pendingData = lines.pop();
+
+ // copy remaining full lines to our pendingLines list
+ this.pendingLines = this.pendingLines.concat(lines);
+
}
- if (multilineValueInProgress && line.match(/^\.$/)) {
- multilineValueInProgress = false;
+ return this.pendingLines.shift();
+ }
+
+ // blocks until an entire message is ready and returns it
+ async _readMessage() {
+ // whether we are searching for the end of a multi-line values
+ // See control-spec section 3.9
+ let handlingMultlineValue = false;
+ let endOfMessageFound = false;
+ const message = [];
+
+ do {
+ const line = await this._readLine();
+ message.push(line);
+
+ if (handlingMultlineValue) {
+ // look for end of multiline
+ if (line.match(/^\.$/)) {
+ handlingMultlineValue = false;
+ }
+ } else {
+ // 'Multiline values' are possible. We avoid interrupting one by detecting it
+ // and waiting for a terminating "." on its own line.
+ // (See control-spec section 3.9 and https://trac.torproject.org/16990#comment:28
+ // Ensure this is the first line of a new message
+ if (message.length === 1 && line.match(/^\d\d\d\+.+?=$/)) {
+ handlingMultlineValue = true;
+ }
+ // look for end of message (note the space character at end of the regex)
+ else if(line.match(/^\d\d\d /)) {
+ if (message.length == 1) {
+ endOfMessageFound = true;
+ } else {
+ let firstReplyCode = message[0].substring(0,3);
+ let lastReplyCode = line.substring(0,3);
+ if (firstReplyCode == lastReplyCode) {
+ endOfMessageFound = true;
+ }
+ }
+ }
+ }
+ } while(!endOfMessageFound);
+
+ // join our lines back together to form one message
+ return message.join("\r\n");
+ }
+
+ async _startMessagePump() {
+ try {
+ while(true) {
+ let message = await this._readMessage();
+ log("controlPort >> " + message);
+ this.mainDispatcher.pushMessage(message);
+ }
+ } catch (err) {
+ this._isOpen = false;
+ for(const cmd of this.commandQueue) {
+ cmd.reject(err);
+ }
+ this.commandQueue = [];
}
- // If line is the last in a message, then pass on the full multiline message.
- if (!multilineValueInProgress &&
- line.match(/^\d\d\d /) &&
- (pendingLines.length === 1 ||
- pendingLines[0].substring(0,3) === line.substring(0,3))) {
- // Combine pending lines to form message.
- let message = pendingLines.join("\r\n");
- log("controlPort >> " + message);
- // Wipe pendingLines before we call onMessage, in case onMessage throws an error.
- pendingLines = [];
- // Pass multiline message to onMessage.
- onMessage(message);
+ }
+
+ _writeNextCommand() {
+ let cmd = this.commandQueue[0];
+ log("controlPort << " + cmd.commandString);
+ this.socket.write(`${cmd.commandString}\r\n`).catch(cmd.reject);
+ }
+
+ async sendCommand(commandString) {
+ if (!this.isOpen()) {
+ throw new Error("ControlSocket not open");
}
- };
+
+ // this promise is resolved either in _handleCommandReply, or
+ // in _startMessagePump (on stream error)
+ return new Promise((resolve, reject) => {
+ let command = {
+ commandString: commandString,
+ resolve: resolve,
+ reject: reject,
+ };
+
+ this.commandQueue.push(command);
+ if (this.commandQueue.length == 1) {
+ this._writeNextCommand();
+ }
+ });
+ }
+
+ _handleCommandReply(message) {
+ let cmd = this.commandQueue.shift();
+ if (message.match(/^2/)) {
+ cmd.resolve(message);
+ } else if (message.match(/^[45]/)) {
+ let myErr = new Error(cmd.commandString + " -> " + message);
+ // Add Tor-specific information to the Error object.
+ let idx = message.indexOf(' ');
+ if (idx > 0) {
+ myErr.torStatusCode = message.substring(0, idx);
+ myErr.torMessage = message.substring(idx);
+ } else {
+ myErr.torStatusCode = message;
+ }
+ cmd.reject(myErr);
+ } else {
+ cmd.reject(new Error(`ControlSocket::_handleCommandReply received unexpected message:\n----\n${message}\n----`));
+ }
+
+ // send next command if one is available
+ if (this.commandQueue.length > 0) {
+ this._writeNextCommand();
+ }
+ }
+
+ _handleNotification(message) {
+ this.notificationDispatcher.pushMessage(message);
+ }
+
+ close() {
+ this.socket.close();
+ this._isOpen = false;
+ }
+
+ addNotificationCallback(regex, callback) {
+ this.notificationDispatcher.addCallback(regex, callback);
+ }
+
+ isOpen() {
+ return this._isOpen;
+ }
};
+// ## io
+// I/O utilities namespace
+
+let io = {};
+
// __io.callbackDispatcher()__.
// Returns dispatcher object with three member functions:
// dispatcher.addCallback(regex, callback), dispatcher.removeCallback(callback),
@@ -222,77 +360,30 @@ io.callbackDispatcher = function () {
addCallback : addCallback };
};
-// __io.matchRepliesToCommands(asyncSend, dispatcher)__.
-// Takes asyncSend(message), an asynchronous send function, and the callback
-// dispatcher, and returns a function Promise<response> sendCommand(command).
-io.matchRepliesToCommands = function (asyncSend, dispatcher) {
- let commandQueue = [],
- sendCommand = function (command, replyCallback, errorCallback) {
- commandQueue.push([command, replyCallback, errorCallback]);
- asyncSend(command);
- };
- // Watch for responses (replies or error messages)
- dispatcher.addCallback(/^[245]\d\d/, function (message) {
- let [command, replyCallback, errorCallback] = commandQueue.shift();
- if (message.match(/^2/) && replyCallback) replyCallback(message);
- if (message.match(/^[45]/) && errorCallback) {
- let myErr = new Error(command + " -> " + message);
- // Add Tor-specific information to the Error object.
- let idx = message.indexOf(' ');
- if (idx > 0) {
- myErr.torStatusCode = message.substring(0, idx);
- myErr.torMessage = message.substring(idx);
- } else {
- myErr.torStatusCode = message;
- }
- errorCallback(myErr);
- }
- });
- // Create and return a version of sendCommand that returns a Promise.
- return command => new Promise(function (replyCallback, errorCallback) {
- sendCommand(command, replyCallback, errorCallback);
- });
-};
-
-// __io.controlSocket(ipcFile, host, port, password, onError)__.
+// __io.controlSocket(ipcFile, host, port, password)__.
// Instantiates and returns a socket to a tor ControlPort at ipcFile or
-// host:port, authenticating with the given password. onError is called with an
-// error object as its single argument whenever an error occurs. Example:
+// host:port, authenticating with the given password. Example:
//
// // Open the socket
-// let socket = controlSocket(undefined, "127.0.0.1", 9151, "MyPassw0rd",
-// function (error) { console.log(error.message || error); });
-// // Send command and receive "250" reply or error message
-// socket.sendCommand(commandText, replyCallback, errorCallback);
+// let socket = await io.controlSocket(undefined, "127.0.0.1", 9151, "MyPassw0rd");
+// // Send command and receive "250" response reply or error is thrown
+// await socket.sendCommand(commandText);
// // Register or deregister for "650" notifications
// // that match regex
// socket.addNotificationCallback(regex, callback);
// socket.removeNotificationCallback(callback);
// // Close the socket permanently
// socket.close();
-io.controlSocket = function (ipcFile, host, port, password, onError) {
- // Produce a callback dispatcher for Tor messages.
- let mainDispatcher = io.callbackDispatcher(),
- // Open the socket and convert format to Tor messages.
- socket = io.asyncSocket(ipcFile, host, port,
- io.onDataFromOnLine(
- io.onLineFromOnMessage(mainDispatcher.pushMessage)),
- onError),
- // Controllers should send commands terminated by CRLF.
- writeLine = function (text) { socket.write(text + "\r\n"); },
- // Create a sendCommand method from writeLine.
- sendCommand = io.matchRepliesToCommands(writeLine, mainDispatcher),
- // Create a secondary callback dispatcher for Tor notification messages.
- notificationDispatcher = io.callbackDispatcher();
- // Pass asynchronous notifications to notification dispatcher.
- mainDispatcher.addCallback(/^650/, notificationDispatcher.pushMessage);
+io.controlSocket = async function (ipcFile, host, port, password) {
+ let socket = new AsyncSocket(ipcFile, host, port);
+ let controlSocket = new ControlSocket(socket);
+
// Log in to control port.
- sendCommand("authenticate " + (password || "")).catch(onError);
+ await controlSocket.sendCommand("authenticate " + (password || ""));
// Activate needed events.
- sendCommand("setevents stream").catch(onError);
- return { close : socket.close, sendCommand : sendCommand,
- addNotificationCallback : notificationDispatcher.addCallback,
- removeNotificationCallback : notificationDispatcher.removeCallback };
+ await controlSocket.sendCommand("setevents stream");
+
+ return controlSocket;
};
// ## utils
@@ -684,13 +775,11 @@ let tor = {};
// redundant instantiation of control sockets.
tor.controllerCache = new Map();
-// __tor.controller(ipcFile, host, port, password, onError)__.
+// __tor.controller(ipcFile, host, port, password)__.
// Creates a tor controller at the given ipcFile or host and port, with the
// given password.
-// onError returns asynchronously whenever a connection error occurs.
-tor.controller = function (ipcFile, host, port, password, onError) {
- let socket = io.controlSocket(ipcFile, host, port, password, onError),
- isOpen = true;
+tor.controller = async function (ipcFile, host, port, password) {
+ let socket = await io.controlSocket(ipcFile, host, port, password);
return { getInfo : key => info.getInfo(socket, key),
getConf : key => info.getConf(socket, key),
onionAuthViewKeys : () => onionAuth.viewKeys(socket),
@@ -701,8 +790,8 @@ tor.controller = function (ipcFile, host, port, password, onError) {
onionAuth.remove(socket, hsAddress),
watchEvent : (type, filter, onData, raw=false) =>
event.watchEvent(socket, type, filter, onData, raw),
- isOpen : () => isOpen,
- close : () => { isOpen = false; socket.close(); },
+ isOpen : () => socket.isOpen(),
+ close : () => { socket.close(); },
sendCommand: cmd => socket.sendCommand(cmd),
};
};
@@ -722,23 +811,24 @@ var configureControlPortModule = function (ipcFile, host, port, password) {
controlPortInfo.password = password;
};
-// __controller(onError)__.
+// __controller(avoidCache)__.
// Instantiates and returns a controller object that is connected and
// authenticated to a Tor ControlPort using the connection parameters
// provided in the most recent call to configureControlPortModule(), if
// the controller doesn't yet exist. Otherwise returns the existing
-// controller to the given ipcFile or host:port.
-// onError is called with an error object as its single argument whenever
-// an error occurs. Example:
+// controller to the given ipcFile or host:port. Throws on error.
//
-// // Get the controller
-// let c = controller(
-// function (error) { console.log(error.message || error); });
+// Example:
+//
+// // Get a new controller
+// const avoidCache = true;
+// let c = controller(avoidCache);
// // Send command and receive `250` reply or error message in a promise:
// let replyPromise = c.getInfo("ip-to-country/16.16.16.16");
// // Close the controller permanently
// c.close();
-var controller = function (onError, avoidCache) {
+var controller = async function (avoidCache) {
+
if (!controlPortInfo.ipcFile && !controlPortInfo.host)
throw new Error("Please call configureControlPortModule first");
@@ -748,18 +838,17 @@ var controller = function (onError, avoidCache) {
// constructor shorthand
const newTorController =
- () => {
- return tor.controller(
+ async () => {
+ return await tor.controller(
controlPortInfo.ipcFile,
controlPortInfo.host,
controlPortInfo.port,
- controlPortInfo.password,
- onError);
+ controlPortInfo.password);
};
// avoid cache so always return a new controller
if (avoidCache) {
- return newTorController();
+ return await newTorController();
}
// first check our cache and see if we already have one
@@ -769,10 +858,44 @@ var controller = function (onError, avoidCache) {
}
// create a new one and store in the map
- cachedController = newTorController();
+ cachedController = await newTorController();
+ // overwrite the close() function to prevent consumers from closing a shared/cached controller
+ cachedController.close = () => {
+ throw new Error("May not close cached Tor Controller as it may be in use");
+ };
+
tor.controllerCache.set(dest, cachedController);
return cachedController;
};
+// __wait_for_controller(avoidCache)
+// Same as controller() function, but explicitly waits until there is a tor daemon
+// to connect to (either launched by tor-launcher, or if we have an existing system
+// tor daemon)
+var wait_for_controller = async function(avoidCache) {
+ // if tor process is running (either ours or system) immediately return controller
+ if (!TorProtocolService.ownsTorDaemon ||
+ TorProtocolService.torProcessStatus == TorProcessStatus.Running) {
+ return await controller(avoidCache);
+ }
+
+ // otherwise we must wait for tor to finish launching before resolving
+ return new Promise((resolve, reject) => {
+ let observer = {
+ observe : async (subject, topic, data) => {
+ if (topic === TorTopics.ProcessIsReady) {
+ try {
+ resolve(await controller(avoidCache));
+ } catch (err) {
+ reject(err);
+ }
+ Services.obs.removeObserver(observer, TorTopics.ProcessIsReady);
+ }
+ },
+ };
+ Services.obs.addObserver(observer, TorTopics.ProcessIsReady);
+ });
+};
+
// Export functions for external use.
-var EXPORTED_SYMBOLS = ["configureControlPortModule", "controller"];
+var EXPORTED_SYMBOLS = ["configureControlPortModule", "controller", "wait_for_controller"];
1
0
[torbutton/master] fixup! Bug 40718: Application Menu items should be sentence case
by richard@torproject.org 17 Jan '22
by richard@torproject.org 17 Jan '22
17 Jan '22
commit 733224de60725b73421a174d26bf60ac32e07626
Author: Pier Angelo Vendrame <pierov(a)torproject.org>
Date: Thu Jan 13 20:11:17 2022 +0100
fixup! Bug 40718: Application Menu items should be sentence case
Closes tor-browser#40776.
---
chrome/locale/en-US/torbutton.dtd | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/chrome/locale/en-US/torbutton.dtd b/chrome/locale/en-US/torbutton.dtd
index cf744d25..4b89fcee 100644
--- a/chrome/locale/en-US/torbutton.dtd
+++ b/chrome/locale/en-US/torbutton.dtd
@@ -2,7 +2,7 @@
<!ENTITY torbutton.context_menu.new_identity_sentence_case "New identity">
<!ENTITY torbutton.context_menu.new_identity_key "I">
<!ENTITY torbutton.context_menu.new_circuit "New Tor Circuit for this Site">
-<!ENTITY torbutton.context_menu.new_circuit_sentence_case "New tor circuit for this site">
+<!ENTITY torbutton.context_menu.new_circuit_sentence_case "New Tor circuit for this site">
<!ENTITY torbutton.context_menu.new_circuit_key "C">
<!ENTITY torbutton.context_menu.networksettings "Tor Network Settings…">
<!ENTITY torbutton.context_menu.networksettings.key "N">
1
0
[tor-browser/tor-browser-91.5.0esr-11.5-1] fixup! Bug 40645: Migrate Moat APIs to Moat.jsm module
by gk@torproject.org 17 Jan '22
by gk@torproject.org 17 Jan '22
17 Jan '22
commit 286900688251c4e89662d34a42e08ff32de14b29
Author: Richard Pospesel <richard(a)torproject.org>
Date: Thu Jan 6 18:27:51 2022 +0100
fixup! Bug 40645: Migrate Moat APIs to Moat.jsm module
---
browser/modules/Moat.jsm | 133 ++++++++++++++++++++++++++++++++++-------------
1 file changed, 98 insertions(+), 35 deletions(-)
diff --git a/browser/modules/Moat.jsm b/browser/modules/Moat.jsm
index b26eb32bdfb3..d02075e4412f 100644
--- a/browser/modules/Moat.jsm
+++ b/browser/modules/Moat.jsm
@@ -16,7 +16,7 @@ const { TorProtocolService } = ChromeUtils.import(
"resource:///modules/TorProtocolService.jsm"
);
-const { TorSettings } = ChromeUtils.import(
+const { TorSettings, TorBridgeSource, TorProxyType } = ChromeUtils.import(
"resource:///modules/TorSettings.jsm"
);
@@ -489,11 +489,10 @@ class MoatRPC {
await ch.asyncOpen(listener, ch);
// wait for response
- const response = await listener.response();
+ const responseJSON = await listener.response();
// parse that JSON
- const retval = JSON.parse(response);
- return retval;
+ return JSON.parse(responseJSON);
}
//
@@ -527,16 +526,16 @@ class MoatRPC {
},
],
};
- const retval = await this._makeRequest("fetch", args);
- if ("errors" in retval) {
- const code = retval.errors[0].code;
- const detail = retval.errors[0].detail;
+ const response = await this._makeRequest("fetch", args);
+ if ("errors" in response) {
+ const code = response.errors[0].code;
+ const detail = response.errors[0].detail;
throw new Error(`MoatRPC: ${detail} (${code})`);
}
- const transport = retval.data[0].transport;
- const image = retval.data[0].image;
- const challenge = retval.data[0].challenge;
+ const transport = response.data[0].transport;
+ const image = response.data[0].image;
+ const challenge = response.data[0].challenge;
return { transport, image, challenge };
}
@@ -568,10 +567,10 @@ class MoatRPC {
},
],
};
- const retval = await this._makeRequest("check", args);
- if ("errors" in retval) {
- const code = retval.errors[0].code;
- const detail = retval.errors[0].detail;
+ const response = await this._makeRequest("check", args);
+ if ("errors" in response) {
+ const code = response.errors[0].code;
+ const detail = response.errors[0].detail;
if (code == 419 && detail === "The CAPTCHA solution was incorrect.") {
return {};
}
@@ -579,12 +578,74 @@ class MoatRPC {
throw new Error(`MoatRPC: ${detail} (${code})`);
}
- const bridges = retval.data[0].bridges;
- const qrcodeImg = qrcode ? retval.data[0].qrcode : null;
+ const bridges = response.data[0].bridges;
+ const qrcodeImg = qrcode ? response.data[0].qrcode : null;
return { bridges, qrcode: qrcodeImg };
}
+ // Convert received settings object to format used by TorSettings module
+ // In the event of error, just return null
+ _fixupSettings(settings) {
+ try {
+ let retval = TorSettings.defaultSettings()
+ if ("bridges" in settings) {
+ retval.bridges.enabled = true;
+ switch(settings.bridges.source) {
+ case "builtin":
+ retval.bridges.source = TorBridgeSource.BuiltIn;
+ retval.bridges.builtin_type = settings.bridges.type;
+ // Tor Browser will periodically update the built-in bridge strings list using the
+ // circumvention_builtin() function, so we can ignore the bridge strings we have received here;
+ // BridgeDB only returns a subset of the available built-in bridges through the circumvention_settings()
+ // function which is fine for our 3rd parties, but we're better off ignoring them in Tor Browser, otherwise
+ // we get in a weird situation of needing to update our built-in bridges in a piece-meal fashion which
+ // seems over-complicated/error-prone
+ break;
+ case "bridgedb":
+ retval.bridges.source = TorBridgeSource.BridgeDB;
+ if (settings.bridges.bridge_strings) {
+ retval.bridges.bridge_strings = settings.bridges.bridge_strings;
+ } else {
+ throw new Error("MoatRPC::_fixupSettings(): Received no bridge-strings for BridgeDB bridge source");
+ }
+ break;
+ default:
+ throw new Error(`MoatRPC::_fixupSettings(): Unexpected bridge source '${settings.bridges.source}'`);
+ }
+ }
+ if ("proxy" in settings) {
+ // TODO: populate proxy settings
+ }
+ if ("firewall" in settings) {
+ // TODO: populate firewall settings
+ }
+ return retval;
+ } catch(ex) {
+ console.log(ex.message);
+ return null;
+ }
+ }
+
+ // Converts a list of settings objects received from BridgeDB to a list of settings objects
+ // understood by the TorSettings module
+ // In the event of error, returns and empty list
+ _fixupSettingsList(settingsList) {
+ try {
+ let retval = [];
+ for (let settings of settingsList) {
+ settings = this._fixupSettings(settings);
+ if (settings != null) {
+ retval.push(settings);
+ }
+ }
+ return retval;
+ } catch (ex) {
+ console.log(ex.message);
+ return [];
+ }
+ }
+
// Request tor settings for the user optionally based on their location (derived
// from their IP), takes the following parameters:
// - transports: optional, an array of transports available to the client; if empty (or not
@@ -596,16 +657,16 @@ class MoatRPC {
// object on the TorSettings module.
// - If the server cannot determine the user's country (and no country code is provided),
// then null is returned
- // - If the country has no associated settings, an empty object is returned
+ // - If the country has no associated settings, an empty array is returned
async circumvention_settings(transports, country) {
const args = {
transports: transports ? transports : [],
country: country,
};
- const retval = await this._makeRequest("circumvention/settings", args);
- if ("errors" in retval) {
- const code = retval.errors[0].code;
- const detail = retval.errors[0].detail;
+ const response = await this._makeRequest("circumvention/settings", args);
+ if ("errors" in response) {
+ const code = response.errors[0].code;
+ const detail = response.errors[0].detail;
if (code == 406) {
console.log("MoatRPC::circumvention_settings(): Cannot automatically determine user's country-code");
// cannot determine user's country
@@ -613,28 +674,30 @@ class MoatRPC {
}
throw new Error(`MoatRPC: ${detail} (${code})`);
+ } else if ("settings" in response) {
+ return this._fixupSettingsList(response.settings);
}
- return retval;
+ return [];
}
// Request a copy of the censorship circumvention map (as if cirumvention_settings were
// queried for all country codes)
//
- // returns a map whose key is an ISO 3166-1 alpha-2 country code and those
+ // returns a map whose key is an ISO 3166-1 alpha-2 country code and whose
// values are arrays of settings objects
async circumvention_map() {
const args = { };
- const retval = await this._makeRequest("circumvention/map", args);
- if ("errors" in retval) {
- const code = retval.errors[0].code;
- const detail = retval.errors[0].detail;
+ const response = await this._makeRequest("circumvention/map", args);
+ if ("errors" in response) {
+ const code = response.errors[0].code;
+ const detail = response.errors[0].detail;
throw new Error(`MoatRPC: ${detail} (${code})`);
}
let map = new Map();
- for (const [country, config] of Object.entries(retval)) {
- map.set(country, config);
+ for (const [country, config] of Object.entries(response)) {
+ map.set(country, this._fixupSettingsList(config.settings));
}
return map;
@@ -650,15 +713,15 @@ class MoatRPC {
const args = {
transports: transports ? transports : [],
};
- const retval = await this._makeRequest("circumvention/builtin", args);
- if ("errors" in retval) {
- const code = retval.errors[0].code;
- const detail = retval.errors[0].detail;
+ const response = await this._makeRequest("circumvention/builtin", args);
+ if ("errors" in response) {
+ const code = response.errors[0].code;
+ const detail = response.errors[0].detail;
throw new Error(`MoatRPC: ${detail} (${code})`);
}
let map = new Map();
- for (const [transport, bridge_strings] of Object.entries(retval)) {
+ for (const [transport, bridge_strings] of Object.entries(response)) {
map.set(transport, bridge_strings);
}
1
0
[tor-browser/tor-browser-91.5.0esr-11.5-1] fixup! Bug 27476: Implement about:torconnect captive portal within Tor Browser
by gk@torproject.org 17 Jan '22
by gk@torproject.org 17 Jan '22
17 Jan '22
commit 7f8276faefc398180879e755a2cf1c87eb28b715
Author: Richard Pospesel <richard(a)torproject.org>
Date: Thu Nov 11 13:03:23 2021 +0100
fixup! Bug 27476: Implement about:torconnect captive portal within Tor Browser
---
.../torconnect/content/aboutTorConnect.js | 6 +-
browser/modules/TorConnect.jsm | 541 +++++++++++++--------
browser/modules/TorProtocolService.jsm | 125 ++++-
3 files changed, 466 insertions(+), 206 deletions(-)
diff --git a/browser/components/torconnect/content/aboutTorConnect.js b/browser/components/torconnect/content/aboutTorConnect.js
index b53f8b13cb80..26b17afb6938 100644
--- a/browser/components/torconnect/content/aboutTorConnect.js
+++ b/browser/components/torconnect/content/aboutTorConnect.js
@@ -144,7 +144,7 @@ class AboutTorConnect {
this.hide(this.elements.cancelButton);
}
- update_AutoConfiguring(state) {
+ update_AutoBootstrapping(state) {
// TODO: noop until this state is used
}
@@ -180,10 +180,6 @@ class AboutTorConnect {
this.hide(this.elements.cancelButton);
}
- update_FatalError(state) {
- // TODO: noop until this state is used
- }
-
update_Bootstrapped(state) {
const hasError = false;
const showProgressbar = true;
diff --git a/browser/modules/TorConnect.jsm b/browser/modules/TorConnect.jsm
index ddc14148eb88..7c8580b5d8a9 100644
--- a/browser/modules/TorConnect.jsm
+++ b/browser/modules/TorConnect.jsm
@@ -10,7 +10,7 @@ const { BrowserWindowTracker } = ChromeUtils.import(
"resource:///modules/BrowserWindowTracker.jsm"
);
-const { TorProtocolService, TorProcessStatus } = ChromeUtils.import(
+const { TorProtocolService, TorProcessStatus, TorTopics, TorBootstrapRequest } = ChromeUtils.import(
"resource:///modules/TorProtocolService.jsm"
);
@@ -18,23 +18,17 @@ const { TorLauncherUtil } = ChromeUtils.import(
"resource://torlauncher/modules/tl-util.jsm"
);
-const { TorSettings, TorSettingsTopics } = ChromeUtils.import(
+const { TorSettings, TorSettingsTopics, TorBridgeSource, TorBuiltinBridgeTypes, TorProxyType } = ChromeUtils.import(
"resource:///modules/TorSettings.jsm"
);
+const { MoatRPC } = ChromeUtils.import("resource:///modules/Moat.jsm");
+
/* Browser observer topis */
const BrowserTopics = Object.freeze({
ProfileAfterChange: "profile-after-change",
});
-/* tor-launcher observer topics */
-const TorTopics = Object.freeze({
- BootstrapStatus: "TorBootstrapStatus",
- BootstrapError: "TorBootstrapError",
- ProcessExited: "TorProcessExited",
- LogHasWarnOrErr: "TorLogHasWarnOrErr",
-});
-
/* Relevant prefs used by tor-launcher */
const TorLauncherPrefs = Object.freeze({
prompt_at_startup: "extensions.torlauncher.prompt_at_startup",
@@ -45,14 +39,12 @@ const TorConnectState = Object.freeze({
Initial: "Initial",
/* In-between initial boot and bootstrapping, users can change tor network settings during this state */
Configuring: "Configuring",
- /* Geo-location and setting bridges/etc */
- AutoConfiguring: "AutoConfiguring",
+ /* Tor is attempting to bootstrap with settings from censorship-circumvention db */
+ AutoBootstrapping: "AutoBootstrapping",
/* Tor is bootstrapping */
Bootstrapping: "Bootstrapping",
- /* Passthrough state back to Configuring or Fatal */
+ /* Passthrough state back to Configuring */
Error: "Error",
- /* An unrecoverable error */
- FatalError: "FatalError",
/* Final state, after successful bootstrap */
Bootstrapped: "Bootstrapped",
/* If we are using System tor or the legacy Tor-Launcher */
@@ -60,60 +52,54 @@ const TorConnectState = Object.freeze({
});
/*
-
- TorConnect State Transitions
-
- ┌──────────────────────┐
- │ Disabled │
- └──────────────────────┘
- ▲
- │ legacyOrSystemTor()
- │
- ┌──────────────────────┐
- ┌────────────────────── │ Initial │ ───────────────────────────┐
- │ └──────────────────────┘ │
- │ │ │
- │ │ beginBootstrap() │
- │ ▼ │
-┌────────────────┐ │ bootstrapComplete() ┌────────────────────────────────────────────────┐ │ beginBootstrap()
-│ Bootstrapped │ ◀──┼────────────────────── │ Bootstrapping │ ◀┼─────────────────┐
-└────────────────┘ │ └────────────────────────────────────────────────┘ │ │
- │ │ ▲ │ │ │
- │ │ cancelBootstrap() │ beginBootstrap() └────┼─────────────┐ │
- │ ▼ │ │ │ │
- │ beginConfigure() ┌────────────────────────────────────────────────┐ │ │ │
- └─────────────────────▶ │ │ │ │ │
- │ │ │ │ │
- beginConfigure() │ │ │ │ │
- ┌──────────────────────────▶ │ Configuring │ │ │ │
- │ │ │ │ │ │
- │ │ │ │ │ │
- │ ┌─────────────────────▶ │ │ │ │ │
- │ │ └────────────────────────────────────────────────┘ │ │ │
- │ │ │ │ │ │ │
- │ │ cancelAutoconfigure() │ autoConfigure() │ ┌────┼─────────────┼───┘
- │ │ ▼ │ │ │ │
- │ │ ┌──────────────────────┐ │ │ │ │
- │ └────────────────────── │ AutoConfiguring │ ─┼────────────────────┘ │ │
- │ └──────────────────────┘ │ │ │
- │ │ │ │ onError() │
- │ │ onError() │ onError() │ │
- │ ▼ ▼ │ │
- │ ┌────────────────────────────────────────────────┐ │ │
- └─────────────────────────── │ Error │ ◀┘ │
- └────────────────────────────────────────────────┘ │
- │ ▲ onError() │
- │ onFatalError() └──────────────────┘
- ▼
- ┌──────────────────────┐
- │ FatalError │
- └──────────────────────┘
-
+ TorConnect State Transitions
+
+ ┌─────────┐ ┌────────┐
+ │ ▼ ▼ │
+ │ ┌──────────────────────────────────────────────────────────┐ │
+ ┌─┼────── │ Error │ ◀───┐ │
+ │ │ └──────────────────────────────────────────────────────────┘ │ │
+ │ │ ▲ │ │
+ │ │ │ │ │
+ │ │ │ │ │
+ │ │ ┌───────────────────────┐ ┌──────────┐ │ │
+ │ │ ┌──── │ Initial │ ────────────────────▶ │ Disabled │ │ │
+ │ │ │ └───────────────────────┘ └──────────┘ │ │
+ │ │ │ │ │ │
+ │ │ │ │ beginBootstrap() │ │
+ │ │ │ ▼ │ │
+ │ │ │ ┌──────────────────────────────────────────────────────────┐ │ │
+ │ │ │ │ Bootstrapping │ ────┘ │
+ │ │ │ └──────────────────────────────────────────────────────────┘ │
+ │ │ │ │ ▲ │ │
+ │ │ │ │ cancelBootstrap() │ beginBootstrap() └────┐ │
+ │ │ │ ▼ │ │ │
+ │ │ │ ┌──────────────────────────────────────────────────────────┐ │ │
+ │ │ └───▶ │ │ ─┼────┘
+ │ │ │ │ │
+ │ │ │ │ │
+ │ │ │ Configuring │ │
+ │ │ │ │ │
+ │ │ │ │ │
+ └─┼─────▶ │ │ │
+ │ └──────────────────────────────────────────────────────────┘ │
+ │ │ ▲ │
+ │ │ beginAutoBootstrap() │ cancelAutoBootstrap() │
+ │ ▼ │ │
+ │ ┌───────────────────────┐ │ │
+ └────── │ AutoBootstrapping │ ─┘ │
+ └───────────────────────┘ │
+ │ │
+ │ │
+ ▼ │
+ ┌───────────────────────┐ │
+ │ Bootstrapped │ ◀───────────────────────────────────┘
+ └───────────────────────┘
*/
-
/* Maps allowed state transitions
TorConnectStateTransitions[state] maps to an array of allowed states to transition to
+ This is just an encoding of the above transition diagram that we verify at runtime
*/
const TorConnectStateTransitions =
Object.freeze(new Map([
@@ -123,22 +109,20 @@ const TorConnectStateTransitions =
TorConnectState.Configuring,
TorConnectState.Error]],
[TorConnectState.Configuring,
- [TorConnectState.AutoConfiguring,
+ [TorConnectState.AutoBootstrapping,
TorConnectState.Bootstrapping,
TorConnectState.Error]],
- [TorConnectState.AutoConfiguring,
+ [TorConnectState.AutoBootstrapping,
[TorConnectState.Configuring,
- TorConnectState.Bootstrapping,
+ TorConnectState.Bootstrapped,
TorConnectState.Error]],
[TorConnectState.Bootstrapping,
[TorConnectState.Configuring,
TorConnectState.Bootstrapped,
TorConnectState.Error]],
[TorConnectState.Error,
- [TorConnectState.Configuring,
- TorConnectState.FatalError]],
+ [TorConnectState.Configuring]],
// terminal states
- [TorConnectState.FatalError, []],
[TorConnectState.Bootstrapped, []],
[TorConnectState.Disabled, []],
]));
@@ -149,9 +133,70 @@ const TorConnectTopics = Object.freeze({
BootstrapProgress: "torconnect:bootstrap-progress",
BootstrapComplete: "torconnect:bootstrap-complete",
BootstrapError: "torconnect:bootstrap-error",
- FatalError: "torconnect:fatal-error",
});
+// The StateCallback is a wrapper around an async function which executes during
+// the lifetime of a TorConnect State. A system is also provided to allow this
+// ongoing function to early-out via a per StateCallback on_transition callback
+// which may be called externally when we need to early-out and move on to another
+// state (for example, from Bootstrapping to Configuring in the event the user
+// cancels a bootstrap attempt)
+class StateCallback {
+
+ constructor(state, callback) {
+ this._state = state;
+ this._callback = callback;
+ this._init();
+ }
+
+ _init() {
+ // this context object is bound to the callback each time transition is
+ // attempted via begin()
+ this._context = {
+ // This callback may be overwritten in the _callback for each state
+ // States may have various pieces of work which need to occur
+ // before they can be exited (eg resource cleanup)
+ // See the _stateCallbacks map for examples
+ on_transition: (nextState) => {},
+
+ // flag used to determine if a StateCallback should early-out
+ // its work
+ _transitioning: false,
+
+ // may be called within the StateCallback to determine if exit is possible
+ get transitioning() {
+ return this._transitioning;
+ }
+ };
+ }
+
+ async begin(...args) {
+ console.log(`TorConnect: Entering ${this._state} state`);
+ this._init();
+ try {
+ // this Promise will block until this StateCallback has completed its work
+ await Promise.resolve(this._callback.call(this._context, ...args));
+ console.log(`TorConnect: Exited ${this._state} state`);
+
+ // handled state transition
+ Services.obs.notifyObservers({state: this._nextState}, TorConnectTopics.StateChange);
+ TorConnect._callback(this._nextState).begin(...this._nextStateArgs);
+ } catch (obj) {
+ TorConnect._changeState(TorConnectState.Error, obj?.message, obj?.details);
+ }
+ }
+
+ transition(nextState, ...args) {
+ this._nextState = nextState;
+ this._nextStateArgs = [...args];
+
+ // calls the on_transition callback to resolve any async work or do per-state cleanup
+ // this call to on_transition should resolve the async work currentlying going on in this.begin()
+ this._context.on_transition(nextState);
+ this._context._transitioning = true;
+ }
+}
+
const TorConnect = (() => {
let retval = {
@@ -161,59 +206,207 @@ const TorConnect = (() => {
_errorMessage: null,
_errorDetails: null,
_logHasWarningOrError: false,
+ _transitionPromise: null,
- /* These functions are called after transitioning to a new state */
- _transitionCallbacks: Object.freeze(new Map([
+ /* These functions represent ongoing work associated with one of our states
+ Some of these functions are mostly empty, apart from defining an
+ on_transition function used to resolve their Promise */
+ _stateCallbacks: Object.freeze(new Map([
/* Initial is never transitioned to */
- [TorConnectState.Initial, null],
- /* Configuring */
- [TorConnectState.Configuring, async (self, prevState) => {
- // TODO move this to the transition function
- if (prevState === TorConnectState.Bootstrapping) {
- await TorProtocolService.torStopBootstrap();
- }
- }],
- /* AutoConfiguring */
- [TorConnectState.AutoConfiguring, async (self, prevState) => {
+ [TorConnectState.Initial, new StateCallback(TorConnectState.Initial, async function() {
+ // The initial state doesn't actually do anything, so here is a skeleton for other
+ // states which do perform work
+ await new Promise(async (resolve, reject) => {
+ // This function is provided to signal to the callback that it is complete.
+ // It is called as a result of _changeState and at the very least must
+ // resolve the root Promise object within the StateCallback function
+ // The on_transition callback may also perform necessary cleanup work
+ this.on_transition = (nextState) => {
+ resolve();
+ };
+
+ try {
+ // each state may have a sequence of async work to do
+ let asyncWork = async () => {};
+ await asyncWork();
- }],
+ // after each block we may check for an opportunity to early-out
+ if (this.transitioning) {
+ return;
+ }
+
+ // repeat the above pattern as necessary
+ } catch(err) {
+ // any thrown exceptions here will trigger a transition to the Error state
+ TorConnect._changeState(TorConnectState.Error, err?.message, err?.details);
+ }
+ });
+ })],
+ /* Configuring */
+ [TorConnectState.Configuring, new StateCallback(TorConnectState.Configuring, async function() {
+ await new Promise(async (resolve, reject) => {
+ this.on_transition = (nextState) => {
+ resolve();
+ };
+ });
+ })],
/* Bootstrapping */
- [TorConnectState.Bootstrapping, async (self, prevState) => {
- let error = await TorProtocolService.connect();
- if (error) {
- self.onError(error.message, error.details);
- } else {
- self._errorMessage = self._errorDetails = null;
- }
- }],
+ [TorConnectState.Bootstrapping, new StateCallback(TorConnectState.Bootstrapping, async function() {
+ // wait until bootstrap completes or we get an error
+ await new Promise(async (resolve, reject) => {
+ const tbr = new TorBootstrapRequest();
+ this.on_transition = async (nextState) => {
+ if (nextState === TorConnectState.Configuring) {
+ // stop bootstrap process if user cancelled
+ await tbr.cancel();
+ }
+ resolve();
+ };
+
+ tbr.onbootstrapstatus = (progress, status) => {
+ TorConnect._updateBootstrapStatus(progress, status);
+ };
+ tbr.onbootstrapcomplete = () => {
+ TorConnect._changeState(TorConnectState.Bootstrapped);
+ };
+ tbr.onbootstraperror = (message, details) => {
+ TorConnect._changeState(TorConnectState.Error, message, details);
+ };
+
+ tbr.bootstrap();
+ });
+ })],
+ /* AutoBootstrapping */
+ [TorConnectState.AutoBootstrapping, new StateCallback(TorConnectState.AutoBootstrapping, async function(countryCode) {
+ await new Promise(async (resolve, reject) => {
+ this.on_transition = (nextState) => {
+ resolve();
+ };
+
+ // lookup user's potential censorship circumvention settings from Moat service
+ try {
+ this.mrpc = new MoatRPC();
+ await this.mrpc.init();
+
+ this.settings = await this.mrpc.circumvention_settings([...TorBuiltinBridgeTypes, "vanilla"], countryCode);
+
+ if (this.transitioning) return;
+
+ if (this.settings === null) {
+ // unable to determine country
+ TorConnect._changeState(TorConnectState.Error, "Unable to determine user country", "DETAILS_STRING");
+ return;
+ } else if (this.settings.length === 0) {
+ // no settings available for country
+ TorConnect._changeState(TorConnectState.Error, "No settings available for your location", "DETAILS_STRING");
+ return;
+ }
+ } catch (err) {
+ TorConnect._changeState(TorConnectState.Error, err?.message, err?.details);
+ return;
+ } finally {
+ // important to uninit MoatRPC object or else the pt process will live as long as tor-browser
+ this.mrpc?.uninit();
+ }
+
+ // apply each of our settings and try to bootstrap with each
+ try {
+ this.originalSettings = TorSettings.getSettings();
+
+ let index = 0;
+ for (let currentSetting of this.settings) {
+ // let us early out if user cancels
+ if (this.transitioning) return;
+
+ console.log(`TorConnect: Attempting Bootstrap with configuration ${++index}/${this.settings.length}`);
+
+ TorSettings.setSettings(currentSetting);
+ await TorSettings.applySettings();
+
+ // build out our bootstrap request
+ const tbr = new TorBootstrapRequest();
+ tbr.onbootstrapstatus = (progress, status) => {
+ TorConnect._updateBootstrapStatus(progress, status);
+ };
+ tbr.onbootstraperror = (message, details) => {
+ console.log(`TorConnect: Auto-Bootstrap error => ${message}; ${details}`);
+ };
+
+ // update transition callback for user cancel
+ this.on_transition = async (nextState) => {
+ if (nextState === TorConnectState.Configuring) {
+ await tbr.cancel();
+ }
+ resolve();
+ };
+
+ // begin bootstrap
+ if (await tbr.bootstrap()) {
+ // persist the current settings to preferences
+ TorSettings.saveToPrefs();
+ TorConnect._changeState(TorConnectState.Bootstrapped);
+ return;
+ }
+ }
+ // bootstrapped failed for all potential settings, so reset daemon to use original
+ TorSettings.setSettings(this.originalSettings);
+ await TorSettings.applySettings();
+ TorSettings.saveToPrefs();
+
+ // only explicitly change state here if something else has not transitioned us
+ if (!this.transitioning) {
+ TorConnect._changeState(TorConnectState.Error, "AutoBootstrapping failed", "DETAILS_STRING");
+ }
+ return;
+ } catch (err) {
+ // restore original settings in case of error
+ try {
+ TorSettings.setSettings(this.originalSettings);
+ await TorSettings.applySettings();
+ } catch(err) {
+ console.log(`TorConnect: Failed to restore original settings => ${err}`);
+ }
+ TorConnect._changeState(TorConnectState.Error, err?.message, err?.details);
+ return;
+ }
+ });
+ })],
/* Bootstrapped */
- [TorConnectState.Bootstrapped, async (self,prevState) => {
- // notify observers of bootstrap completion
- Services.obs.notifyObservers(null, TorConnectTopics.BootstrapComplete);
- }],
+ [TorConnectState.Bootstrapped, new StateCallback(TorConnectState.Bootstrapped, async function() {
+ await new Promise((resolve, reject) => {
+ // on_transition not defined because no way to leave Bootstrapped state
+ // notify observers of bootstrap completion
+ Services.obs.notifyObservers(null, TorConnectTopics.BootstrapComplete);
+ });
+ })],
/* Error */
- [TorConnectState.Error, async (self, prevState, errorMessage, errorDetails, fatal) => {
- self._errorMessage = errorMessage;
- self._errorDetails = errorDetails;
+ [TorConnectState.Error, new StateCallback(TorConnectState.Error, async function(errorMessage, errorDetails) {
+ await new Promise((resolve, reject) => {
+ this.on_transition = async(nextState) => {
+ resolve();
+ };
- Services.obs.notifyObservers({message: errorMessage, details: errorDetails}, TorConnectTopics.BootstrapError);
- if (fatal) {
- self.onFatalError();
- } else {
- self.beginConfigure();
- }
- }],
- /* FatalError */
- [TorConnectState.FatalError, async (self, prevState) => {
- Services.obs.notifyObservers(null, TorConnectTopics.FatalError);
- }],
- /* Disabled */
- [TorConnectState.Disabled, (self, prevState) => {
+ TorConnect._errorMessage = errorMessage;
+ TorConnect._errorDetails = errorDetails;
- }],
+ Services.obs.notifyObservers({message: errorMessage, details: errorDetails}, TorConnectTopics.BootstrapError);
+
+ TorConnect._changeState(TorConnectState.Configuring);
+ });
+ })],
+ /* Disabled */
+ [TorConnectState.Disabled, new StateCallback(TorConnectState.Disabled, async function() {
+ await new Promise((resolve, reject) => {
+ // no-op, on_transition not defined because no way to leave Disabled state
+ });
+ })],
])),
- _changeState: async function(newState, ...args) {
+ _callback: function(state) {
+ return this._stateCallbacks.get(state);
+ },
+
+ _changeState: function(newState, ...args) {
const prevState = this._state;
// ensure this is a valid state transition
@@ -221,28 +414,40 @@ const TorConnect = (() => {
throw Error(`TorConnect: Attempted invalid state transition from ${prevState} to ${newState}`);
}
- console.log(`TorConnect: transitioning state from ${prevState} to ${newState}`);
+ console.log(`TorConnect: Try transitioning from ${prevState} to ${newState}`);
// set our new state first so that state transitions can themselves trigger
// a state transition
this._state = newState;
- // call our transition function and forward any args
- await this._transitionCallbacks.get(newState)(this, prevState, ...args);
+ // call our state function and forward any args
+ this._callback(prevState).transition(newState, ...args);
+ },
+
+ _updateBootstrapStatus: function(progress, status) {
+ this._bootstrapProgress= progress;
+ this._bootstrapStatus = status;
- Services.obs.notifyObservers({state: newState}, TorConnectTopics.StateChange);
+ console.log(`TorConnect: Bootstrapping ${this._bootstrapProgress}% complete (${this._bootstrapStatus})`);
+ Services.obs.notifyObservers({
+ progress: TorConnect._bootstrapProgress,
+ status: TorConnect._bootstrapStatus,
+ hasWarnings: TorConnect._logHasWarningOrError
+ }, TorConnectTopics.BootstrapProgress);
},
// init should be called on app-startup in MainProcessingSingleton.jsm
- init : function() {
- console.log("TorConnect: Init");
+ init: function() {
+ console.log("TorConnect: init()");
// delay remaining init until after profile-after-change
Services.obs.addObserver(this, BrowserTopics.ProfileAfterChange);
+
+ this._callback(TorConnectState.Initial).begin();
},
observe: async function(subject, topic, data) {
- console.log(`TorConnect: observed ${topic}`);
+ console.log(`TorConnect: Observed ${topic}`);
switch(topic) {
@@ -250,19 +455,17 @@ const TorConnect = (() => {
case BrowserTopics.ProfileAfterChange: {
if (TorLauncherUtil.useLegacyLauncher || !TorProtocolService.ownsTorDaemon) {
// Disabled
- this.legacyOrSystemTor();
+ this._changeState(TorConnectState.Disabled);
} else {
let observeTopic = (topic) => {
Services.obs.addObserver(this, topic);
- console.log(`TorConnect: observing topic '${topic}'`);
+ console.log(`TorConnect: Observing topic '${topic}'`);
};
// register the Tor topics we always care about
- for (const topicKey in TorTopics) {
- const topic = TorTopics[topicKey];
- observeTopic(topic);
- }
- observeTopic(TorSettingsTopics.Ready);
+ observeTopic(TorTopics.ProcessExited);
+ observeTopic(TorTopics.LogHasWarnOrErr);
+ observeTopic(TorSettingsTopics.Ready);
}
Services.obs.removeObserver(this, topic);
break;
@@ -271,45 +474,13 @@ const TorConnect = (() => {
case TorSettingsTopics.Ready: {
if (this.shouldQuickStart) {
// Quickstart
- this.beginBootstrap();
+ this._changeState(TorConnectState.Bootstrapping);
} else {
// Configuring
- this.beginConfigure();
+ this._changeState(TorConnectState.Configuring);
}
break;
}
- /* Updates our bootstrap status */
- case TorTopics.BootstrapStatus: {
- if (this._state != TorConnectState.Bootstrapping) {
- console.log(`TorConnect: observed ${TorTopics.BootstrapStatus} topic while in state TorConnectState.${this._state}`);
- break;
- }
-
- const obj = subject?.wrappedJSObject;
- if (obj) {
- this._bootstrapProgress= obj.PROGRESS;
- this._bootstrapStatus = TorLauncherUtil.getLocalizedBootstrapStatus(obj, "TAG");
-
- console.log(`TorConnect: Bootstrapping ${this._bootstrapProgress}% complete (${this._bootstrapStatus})`);
- Services.obs.notifyObservers({
- progress: this._bootstrapProgress,
- status: this._bootstrapStatus,
- hasWarnings: this._logHasWarningOrError
- }, TorConnectTopics.BootstrapProgress);
-
- if (this._bootstrapProgress === 100) {
- this.bootstrapComplete();
- }
- }
- break;
- }
- /* Handle bootstrap error*/
- case TorTopics.BootstrapError: {
- const obj = subject?.wrappedJSObject;
- await TorProtocolService.torStopBootstrap();
- this.onError(obj.message, obj.details);
- break;
- }
case TorTopics.LogHasWarnOrErr: {
this._logHasWarningOrError = true;
break;
@@ -365,55 +536,27 @@ const TorConnect = (() => {
},
/*
- These functions tell TorConnect to transition states
+ These functions allow external consumers to tell TorConnect to transition states
*/
- legacyOrSystemTor: function() {
- console.log("TorConnect: legacyOrSystemTor()");
- this._changeState(TorConnectState.Disabled);
- },
-
beginBootstrap: function() {
console.log("TorConnect: beginBootstrap()");
this._changeState(TorConnectState.Bootstrapping);
},
- beginConfigure: function() {
- console.log("TorConnect: beginConfigure()");
- this._changeState(TorConnectState.Configuring);
- },
-
- autoConfigure: function() {
- console.log("TorConnect: autoConfigure()");
- // TODO: implement
- throw Error("TorConnect: not implemented");
- },
-
- cancelAutoConfigure: function() {
- console.log("TorConnect: cancelAutoConfigure()");
- // TODO: implement
- throw Error("TorConnect: not implemented");
- },
-
cancelBootstrap: function() {
console.log("TorConnect: cancelBootstrap()");
this._changeState(TorConnectState.Configuring);
},
- bootstrapComplete: function() {
- console.log("TorConnect: bootstrapComplete()");
- this._changeState(TorConnectState.Bootstrapped);
- },
-
- onError: function(message, details) {
- console.log("TorConnect: onError()");
- this._changeState(TorConnectState.Error, message, details, false);
+ beginAutoBootstrap: function(countryCode) {
+ console.log("TorConnect: beginAutoBootstrap()");
+ this._changeState(TorConnectState.AutoBootstrapping, countryCode);
},
- onFatalError: function() {
- console.log("TorConnect: onFatalError()");
- // TODO: implement
- throw Error("TorConnect: not implemented");
+ cancelAutoBootstrap: function() {
+ console.log("TorConnect: cancelAutoBootstrap()");
+ this._changeState(TorConnectState.Configuring);
},
/*
@@ -490,7 +633,7 @@ const TorConnect = (() => {
};
let redirectUris = uris.map(uriToRedirectUri);
- console.log(`TorConnect: will load after bootstrap => [${uris.map((uri) => {return uri.spec;}).join(", ")}]`);
+ console.log(`TorConnect: Will load after bootstrap => [${uris.map((uri) => {return uri.spec;}).join(", ")}]`);
return redirectUris;
},
};
diff --git a/browser/modules/TorProtocolService.jsm b/browser/modules/TorProtocolService.jsm
index b8678fbca9aa..ac6d643691f6 100644
--- a/browser/modules/TorProtocolService.jsm
+++ b/browser/modules/TorProtocolService.jsm
@@ -2,12 +2,18 @@
"use strict";
-var EXPORTED_SYMBOLS = ["TorProtocolService", "TorProcessStatus"];
+var EXPORTED_SYMBOLS = ["TorProtocolService", "TorProcessStatus", "TorTopics", "TorBootstrapRequest"];
const { Services } = ChromeUtils.import(
"resource://gre/modules/Services.jsm"
);
+const { setTimeout, clearTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm");
+
+const { TorLauncherUtil } = ChromeUtils.import(
+ "resource://torlauncher/modules/tl-util.jsm"
+);
+
// see tl-process.js
const TorProcessStatus = Object.freeze({
Unknown: 0,
@@ -16,6 +22,14 @@ const TorProcessStatus = Object.freeze({
Exited: 3,
});
+/* tor-launcher observer topics */
+const TorTopics = Object.freeze({
+ BootstrapStatus: "TorBootstrapStatus",
+ BootstrapError: "TorBootstrapError",
+ ProcessExited: "TorProcessExited",
+ LogHasWarnOrErr: "TorLogHasWarnOrErr",
+});
+
/* Browser observer topis */
const BrowserTopics = Object.freeze({
ProfileAfterChange: "profile-after-change",
@@ -360,4 +374,111 @@ var TorProtocolService = {
return TorProcessStatus.Unknown;
},
};
-TorProtocolService.init();
\ No newline at end of file
+TorProtocolService.init();
+
+// modeled after XMLHttpRequest
+// nicely encapsulates the observer register/unregister logic
+class TorBootstrapRequest {
+ constructor() {
+ // number of ms to wait before we abandon the bootstrap attempt
+ // a value of 0 implies we never wait
+ this.timeout = 0;
+ // callbacks for bootstrap process status updates
+ this.onbootstrapstatus = (progress, status) => {};
+ this.onbootstrapcomplete = () => {};
+ this.onbootstraperror = (message, details) => {};
+
+ // internal resolve() method for bootstrap
+ this._bootstrapPromiseResolve = null;
+ this._bootstrapPromise = null;
+ this._timeoutID = null;
+ }
+
+ async observe(subject, topic, data) {
+ const obj = subject?.wrappedJSObject;
+ switch(topic) {
+ case TorTopics.BootstrapStatus: {
+ const progress = obj.PROGRESS;
+ const status = TorLauncherUtil.getLocalizedBootstrapStatus(obj, "TAG");
+ if (this.onbootstrapstatus) {
+ this.onbootstrapstatus(progress, status);
+ }
+ if (progress === 100) {
+ if (this.onbootstrapcomplete) {
+ this.onbootstrapcomplete();
+ }
+ this._bootstrapPromiseResolve(true);
+ clearTimeout(this._timeoutID);
+ }
+
+ break;
+ }
+ case TorTopics.BootstrapError: {
+ // first stop our bootstrap timeout before handling the error
+ clearTimeout(this._timeoutID);
+
+ await TorProtocolService.torStopBootstrap();
+
+ const message = obj.message;
+ const details = obj.details;
+ if (this.onbootstraperror) {
+ this.onbootstraperror(message, details);
+ }
+ this._bootstrapPromiseResolve(false);
+ break;
+ }
+ }
+ }
+
+ // resolves 'true' if bootstrap succeeds, false otherwise
+ async bootstrap() {
+ if (this._bootstrapPromise) return this._bootstrapPromise;
+
+ this._bootstrapPromise = new Promise(async (resolve, reject) => {
+ this._bootstrapPromiseResolve = resolve;
+
+ // register ourselves to listen for bootstrap events
+ Services.obs.addObserver(this, TorTopics.BootstrapStatus);
+ Services.obs.addObserver(this, TorTopics.BootstrapError);
+
+ // optionally cancel bootstrap after a given timeout
+ if (this.timeout > 0) {
+ this._timeoutID = setTimeout(async () => {
+ await TorProtocolService.torStopBootstrap();
+ if (this.onbootstraperror) {
+ this.onbootstraperror("Tor Bootstrap process timed out", `Bootstrap attempt abandoned after waiting ${this.timeout} ms`);
+ }
+ this._bootstrapPromiseResolve(false);
+ }, this.timeout);
+ }
+
+ // wait for bootstrapping to begin and maybe handle error
+ let err = await TorProtocolService.connect();
+ if (err) {
+ clearTimeout(this._timeoutID);
+ await TorProtocolService.torStopBootstrap();
+
+ const message = err.message;
+ const details = err.details;
+ if (this.onbootstraperror) {
+ this.onbootstraperror(message, details);
+ }
+ this._bootstrapPromiseResolve(false);
+ }
+ }).finally(() => {
+ // and remove ourselves once bootstrap is resolved
+ Services.obs.removeObserver(this, TorTopics.BootstrapStatus);
+ Services.obs.removeObserver(this, TorTopics.BootstrapError);
+ });
+
+ return this._bootstrapPromise;
+ }
+
+ async cancel() {
+ clearTimeout(this._timeoutID);
+
+ await TorProtocolService.torStopBootstrap();
+
+ this._bootstrapPromiseResolve(false);
+ }
+};
1
0
[tor-browser/tor-browser-91.5.0esr-11.5-1] fixup! Bug 40597: Implement TorSettings module
by gk@torproject.org 17 Jan '22
by gk@torproject.org 17 Jan '22
17 Jan '22
commit 58466dd7347595752663d96bdc6e4f2bdcebbe5f
Author: Richard Pospesel <richard(a)torproject.org>
Date: Wed Nov 10 16:03:45 2021 +0100
fixup! Bug 40597: Implement TorSettings module
resolves tor-browser#40598
---
browser/modules/TorSettings.jsm | 243 ++++++++++------------------------------
1 file changed, 61 insertions(+), 182 deletions(-)
diff --git a/browser/modules/TorSettings.jsm b/browser/modules/TorSettings.jsm
index 6d2a6c4a07cf..1b5b564e1e62 100644
--- a/browser/modules/TorSettings.jsm
+++ b/browser/modules/TorSettings.jsm
@@ -303,214 +303,49 @@ const TorSettings = (() => {
return settings;
},
- /* try and load our settings, and register observers */
+ /* load or init our settings, and register observers */
init: function() {
if (TorProtocolService.ownsTorDaemon) {
// if the settings branch exists, load settings from prefs
if (Services.prefs.getBoolPref(TorSettingsPrefs.enabled, false)) {
this.loadFromPrefs();
- Services.obs.notifyObservers(null, TorSettingsTopics.Ready);
+ } else {
+ // otherwise load defaults
+ this._settings = this.defaultSettings();
}
Services.obs.addObserver(this, BrowserTopics.ProfileAfterChange);
Services.obs.addObserver(this, TorTopics.ProcessIsReady);
}
},
- /* wait for relevant life-cycle events to load and/or apply saved settings */
+ /* wait for relevant life-cycle events to apply saved settings */
observe: async function(subject, topic, data) {
- console.log(`TorSettings: observed ${topic}`);
+ console.log(`TorSettings: Observed ${topic}`);
- // once the process is ready, we need to apply our settings
+ // once the tor daemon is ready, we need to apply our settings
let handleProcessReady = async () => {
- Services.obs.removeObserver(this, TorTopics.ProcessIsReady);
- if (this._settings == null) {
- // load settings from tor if our load in init() failed and save them to prefs
- await this.loadLegacy();
- this.saveToPrefs();
- } else {
- // push down settings to tor
- await this.applySettings();
- }
+ // push down settings to tor
+ await this.applySettings();
+ console.log("TorSettings: Ready");
Services.obs.notifyObservers(null, TorSettingsTopics.Ready);
};
switch (topic) {
case BrowserTopics.ProfileAfterChange: {
+ Services.obs.removeObserver(this, BrowserTopics.ProfileAfterChange);
if (TorProtocolService.torProcessStatus == TorProcessStatus.Running) {
await handleProcessReady();
}
}
break;
case TorTopics.ProcessIsReady: {
+ Services.obs.removeObserver(this, TorTopics.ProcessIsReady);
await handleProcessReady();
}
break;
}
},
- // load our settings from old locations (misc prefs and from tor daemon)
- // TODO: remove this after some time has elapsed to ensure users have migrated to pref settings
- loadLegacy: async function() {
- console.log("TorSettings: loadLegacy()");
-
- let settings = this.defaultSettings();
-
- /* Quickstart */
- settings.quickstart.enabled = Services.prefs.getBoolPref(TorLauncherPrefs.quickstart, false);
-
- /* Bridges
-
- So the way tor-launcher determines the origin of the configured bridges is a bit
- weird and depends on inferring our scenario based on some firefox prefs and the
- relationship between the saved list of bridges in about:config vs the list saved in torrc
-
- first off, if "extensions.torlauncher.default_bridge_type" is set to one of our
- builtin default types (obfs4, meek-azure, snowflake, etc) then we provide the
- bridges in "extensions.torlauncher.default_bridge.*" (filtered by our default_bridge_type)
-
- next, we compare the list of bridges saved in torrc to the bridges stored in the
- "extensions.torlauncher.bridgedb_bridge."" branch. If they match *exactly* then we assume
- the bridges were retrieved from BridgeDB and use those. If the torrc list is empty then we know
- we have no bridge settings
-
- finally, if none of the previous conditions are not met, it is assumed the bridges stored in
- torrc are user-provided
- */
-
- let builtinType = Services.prefs.getCharPref(TorLauncherPrefs.default_bridge_type, null);
-
- // check if source is built-in
- if (builtinType) {
- let builtinBridgeStrings = getBuiltinBridgeStrings(builtinType);
- if (builtinBridgeStrings.length > 0) {
- settings.bridges.enabled = true;
- settings.bridges.source = TorBridgeSource.BuiltIn;
- settings.bridges.builtin_type = builtinType;
- settings.bridges.bridge_strings = builtinBridgeStrings;
- }
- } else {
- // get our currently configured bridges from tor
- let torrcBridgeStrings = await (async () => {
- let bridgeList = await TorProtocolService.readStringArraySetting(TorConfigKeys.bridgeList);
- let retval = [];
- for (const line of bridgeList) {
- let trimmedLine = line.trim();
- if (trimmedLine) {
- retval.push(trimmedLine);
- }
- }
- return retval;
- })();
-
- // torrc has bridges configured
- if (torrcBridgeStrings.length > 0) {
- // compare tor's bridges to our saved bridgedb bridges
- let bridgedbBBridgeStrings = (() => {
- let bridgeBranch = Services.prefs.getBranch(TorLauncherPrefs.bridgedb_bridge);
- let bridgeBranchPrefs = bridgeBranch.getChildList("");
- // the child prefs do not come in any particular order so sort the keys
- // so the values can be compared to what we get out off torrc
- bridgeBranchPrefs.sort();
-
- // just assume all of the prefs under the parent point to valid bridge string
- let retval = bridgeBranchPrefs.map(key =>
- bridgeBranch.getCharPref(key).trim()
- );
- return retval;
- })();
-
- let arraysEqual = (left, right) => {
- if (left.length != right.length) {
- return false;
- }
- const length = left.length;
- for (let i = 0; i < length; ++i) {
- if (left[i] != right[i]) {
- return false;
- }
- }
- return true;
- };
-
- if (arraysEqual(torrcBridgeStrings, bridgedbBBridgeStrings)) {
- settings.bridges.enabled = true;
- settings.bridges.source = TorBridgeSource.BridgeDB;
- settings.bridges.builtin_type = null;
- settings.bridges.bridge_strings = torrcBridgeStrings;
- } else {
- settings.bridges.enabled = true;
- settings.bridges.source = TorBridgeSource.UserProvided;
- settings.bridges.builtin_type = null;
- settings.bridges.bridge_strings = torrcBridgeStrings;
- }
- } else {
- // tor has no bridge strings saved, so bridges not in use
- settings.bridges.enabled = false;
- settings.bridges.source = TorBridgeSource.Invalid;
- settings.bridges.builtin_type = null;
- settings.bridges.bridge_strings = [];
- }
- }
-
- /* Proxy */
-
- let proxyString = null;
- if (proxyString = await TorProtocolService.readStringSetting(TorConfigKeys.socks4Proxy)) {
- let [address, port] = parseAddrPort(proxyString);
-
- settings.proxy.enabled = true;
- settings.proxy.type = TorProxyType.Socks4;
- settings.proxy.address = address;
- settings.proxy.port = port;
- settings.proxy.username = null;
- settings.proxy.password = null;
- } else if (proxyString = await TorProtocolService.readStringSetting(TorConfigKeys.socks5Proxy)) {
- let [address, port] = parseAddrPort(proxyString);
- let username = await TorProtocolService.readStringSetting(TorConfigKeys.socks5ProxyUsername);
- let password = await TorProtocolService.readStringSetting(TorConfigKeys.socks5ProxyPassword);
-
- settings.proxy.enabled = true;
- settings.proxy.type = TorProxyType.Socks5;
- settings.proxy.address = address;
- settings.proxy.port = port;
- settings.proxy.username = username;
- settings.proxy.password = password;
- } else if (proxyString = await TorProtocolService.readStringSetting(TorConfigKeys.httpsProxy)) {
- let [address, port] = parseAddrPort(proxyString);
- let authenticator = await TorProtocolService.readStringSetting(TorConfigKeys.httpsProxyAuthenticator);
- let [username, password] = parseUsernamePassword(authenticator);
-
- settings.proxy.enabled = true;
- settings.proxy.type = TorProxyType.HTTPS;
- settings.proxy.address = address;
- settings.proxy.port = port;
- settings.proxy.username = username;
- settings.proxy.password = password;
- } else {
- settings.proxy.enabled = false;
- settings.proxy.type = TorProxyType.Invalid;
- settings.proxy.address = null;
- settings.proxy.port = 0;
- settings.proxy.username = null;
- settings.proxy.password = null;
- }
-
- /* Firewall */
- let firewallString = await TorProtocolService.readStringSetting(TorConfigKeys.reachableAddresses);
- if (firewallString) {
- let allowedPorts = parseAddrPortList(firewallString);
- settings.firewall.enabled = allowedPorts.length > 0;
- settings.firewall.allowed_ports = allowedPorts;
- } else {
- settings.firewall.enabled = false;
- settings.firewall.allowed_ports = [];
- }
-
- this._settings = settings;
-
- return this;
- },
-
// load our settings from prefs
loadFromPrefs: function() {
console.log("TorSettings: loadFromPrefs()");
@@ -704,16 +539,60 @@ const TorSettings = (() => {
return this;
},
- /* Getters and Setters */
+ // set all of our settings at once from a settings object
+ setSettings: function(settings) {
+ console.log("TorSettings: setSettings()");
+ let backup = this.getSettings();
+
+ try {
+ if (settings.bridges.enabled) {
+ this._settings.bridges.enabled = true;
+ this._settings.bridges.source = settings.bridges.source;
+ switch(settings.bridges.source) {
+ case TorBridgeSource.BridgeDB:
+ case TorBridgeSource.UserProvided:
+ this._settings.bridges.bridge_strings = settings.bridges.bridge_strings
+ break;
+ case TorBridgeSource.BuiltIn: {
+ this._settings.bridges.builtin_type = settings.bridges.builtin_type;
+ let bridgeStrings = getBuiltinBridgeStrings(settings.bridges.builtin_type);
+ if (bridgeStrings.length > 0) {
+ this._settings.bridges.bridge_strings = bridgeStrings;
+ } else {
+ throw new Error(`No available builtin bridges of type ${settings.bridges.builtin_type}`);
+ }
+ break;
+ }
+ default:
+ throw new Error(`Bridge source '${settings.source}' is not a valid source`);
+ }
+ } else {
+ this.bridges.enabled = false;
+ }
+
+ // TODO: proxy and firewall
+ } catch(ex) {
+ this._settings = backup;
+ console.log(`TorSettings: setSettings failed => ${ex.message}`);
+ }
+
+ console.log("TorSettings: setSettings result");
+ console.log(this._settings);
+ },
+
+ // get a copy of all our settings
+ getSettings: function() {
+ console.log("TorSettings: getSettings()");
+ // TODO: replace with structuredClone someday (post esr94): https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
+ return JSON.parse(JSON.stringify(this._settings));
+ },
+ /* Getters and Setters */
// Quickstart
get quickstart() {
return {
- // Avoid a race-condition on first-start where this property
- // may be accessed before `self._settings` is initialized.
- // This work-around can be removed when #40598 is resolved.
- get enabled() { return (self._settings ? self._settings.quickstart.enabled : false); },
+ get enabled() { return self._settings.quickstart.enabled; },
set enabled(val) {
if (val != self._settings.quickstart.enabled)
{
1
0
[tor-browser-spec/master] Merge remote-tracking branch 'gitlab-tpo/merge-requests/15'
by boklm@torproject.org 14 Jan '22
by boklm@torproject.org 14 Jan '22
14 Jan '22
commit e4f44d36b4118edaed5bd2158864289549ee4a90
Merge: 67f8b30 4663f9b
Author: Nicolas Vigier <boklm(a)torproject.org>
Date: Fri Jan 14 18:02:20 2022 +0100
Merge remote-tracking branch 'gitlab-tpo/merge-requests/15'
processes/ReleaseProcess | 30 ++++++++++++++++++++++--------
1 file changed, 22 insertions(+), 8 deletions(-)
1
0