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

Keyboard Shortcuts

Thread View

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

tbb-commits

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

  • 1 participants
  • 20451 discussions
[Git][tpo/applications/mullvad-browser][mullvad-browser-140.2.0esr-15.0-1] fixup! Firefox preference overrides.
by Pier Angelo Vendrame (@pierov) 09 Sep '25

09 Sep '25
Pier Angelo Vendrame pushed to branch mullvad-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Mullvad Browser Commits: 8998794a by Pier Angelo Vendrame at 2025-09-09T16:00:06+02:00 fixup! Firefox preference overrides. BB 43959: Switch to Noto Color Emoji on Linux and Windows. It has better compatibility than Twemoji Mozilla and upstream also did it in Bug 1939359 (for Linux). We don't use Segoe UI Emoji on Windows, so we enable Noto Color Emoji also on Windows. - - - - - 1 changed file: - browser/app/profile/001-base-profile.js Changes: ===================================== browser/app/profile/001-base-profile.js ===================================== @@ -883,8 +883,9 @@ pref("font.name-list.monospace.x-unicode", "Menlo, Courier New, Noto Sans Baline #endif #ifdef XP_WIN -pref("font.system.whitelist", "Arial, Cambria Math, Consolas, Courier New, Georgia, Lucida Console, MS Gothic, MS ゴシック, MS PGothic, MS Pゴシック, MV Boli, Malgun Gothic, Microsoft Himalaya, Microsoft JhengHei, Microsoft YaHei, 微软雅黑, Segoe UI, SimSun, 宋体, Sylfaen, Tahoma, Times New Roman, Verdana, Twemoji Mozilla, Noto Sans Adlam, Noto Sans Balinese, Noto Sans Bamum, Noto Sans Bassa Vah, Noto Sans Batak, Noto Sans Bengali, Noto Sans Buginese, Noto Sans Buhid, Noto Sans Canadian Aboriginal, Noto Sans Chakma, Noto Sans Cham, Noto Sans Cherokee, Noto Sans Coptic, Noto Sans Deseret, Noto Sans Devanagari, Noto Sans Elbasan, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Grantha, Noto Sans Gujarati, Noto Sans Gunjala Gondi, Noto Sans Gurmukhi, Noto Sans Hanifi Rohingya, Noto Sans Hanunoo, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Javanese, Noto Sans Kayah Li, Noto Sans Khojki, Noto Sans Khudawadi, Noto Sans Lao, Noto Sans Lepcha, Noto Sans Limbu, Noto Sans Lisu, Noto Sans Mahajani, Noto Sans Malayalam, Noto Sans Mandaic, Noto Sans Masaram Gondi, Noto Sans Medefaidrin, Noto Sans Meetei Mayek, Noto Sans Mende Kikakui, Noto Sans Miao, Noto Sans Modi, Noto Sans Mongolian, Noto Sans Mro, Noto Sans Multani, Noto Sans Newa, Noto Sans New Tai Lue, Noto Sans NKo, Noto Sans Ol Chiki, Noto Sans Oriya, Noto Sans Osage, Noto Sans Osmanya, Noto Sans Pahawh Hmong, Noto Sans Pau Cin Hau, Noto Sans Rejang, Noto Sans Runic, Noto Sans Samaritan, Noto Sans Saurashtra, Noto Sans Sharada, Noto Sans Shavian, Noto Sans Sinhala, Noto Sans Sora Sompeng, Noto Sans Soyombo, Noto Sans Sundanese, Noto Sans Syloti Nagri, Noto Sans Symbols 2, Noto Sans Symbols, Noto Sans Syriac, Noto Sans Tagalog, Noto Sans Tagbanwa, Noto Sans Tai Le, Noto Sans Tai Tham, Noto Sans Tai Viet, Noto Sans Takri, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Tifinagh Adrar, Noto Sans Tifinagh Agraw Imazighen, Noto Sans Tifinagh Ahaggar, Noto Sans Tifinagh Air, Noto Sans Tifinagh APT, Noto Sans Tifinagh Azawagh, Noto Sans Tifinagh Ghat, Noto Sans Tifinagh Hawad, Noto Sans Tifinagh, Noto Sans Tifinagh Rhissa Ixa, Noto Sans Tifinagh SIL, Noto Sans Tifinagh Tawellemmet, Noto Sans Tirhuta, Noto Sans Vai, Noto Sans Wancho, Noto Sans Warang Citi, Noto Sans Yi, Noto Sans Zanabazar Square, Noto Serif Balinese, Noto Serif Bengali, Noto Serif Devanagari, Noto Serif Dogra, Noto Serif Ethiopic, Noto Serif Georgian, Noto Serif Grantha, Noto Serif Gujarati, Noto Serif Gurmukhi, Noto Serif Kannada, Noto Serif Khmer, Noto Serif Khojki, Noto Serif Lao, Noto Serif Malayalam, Noto Serif Myanmar, Noto Serif NP Hmong, Noto Serif Sinhala, Noto Serif Tamil, Noto Serif Telugu, Noto Serif Tibetan, Noto Serif Yezidi, Noto Naskh Arabic, Noto Sans, Noto Serif, Pyidaungsu"); +pref("font.system.whitelist", "Arial, Cambria Math, Consolas, Courier New, Georgia, Lucida Console, MS Gothic, MS ゴシック, MS PGothic, MS Pゴシック, MV Boli, Malgun Gothic, Microsoft Himalaya, Microsoft JhengHei, Microsoft YaHei, 微软雅黑, Segoe UI, SimSun, 宋体, Sylfaen, Tahoma, Times New Roman, Verdana, Noto Color Emoji, Noto Sans Adlam, Noto Sans Balinese, Noto Sans Bamum, Noto Sans Bassa Vah, Noto Sans Batak, Noto Sans Bengali, Noto Sans Buginese, Noto Sans Buhid, Noto Sans Canadian Aboriginal, Noto Sans Chakma, Noto Sans Cham, Noto Sans Cherokee, Noto Sans Coptic, Noto Sans Deseret, Noto Sans Devanagari, Noto Sans Elbasan, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Grantha, Noto Sans Gujarati, Noto Sans Gunjala Gondi, Noto Sans Gurmukhi, Noto Sans Hanifi Rohingya, Noto Sans Hanunoo, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Javanese, Noto Sans Kayah Li, Noto Sans Khojki, Noto Sans Khudawadi, Noto Sans Lao, Noto Sans Lepcha, Noto Sans Limbu, Noto Sans Lisu, Noto Sans Mahajani, Noto Sans Malayalam, Noto Sans Mandaic, Noto Sans Masaram Gondi, Noto Sans Medefaidrin, Noto Sans Meetei Mayek, Noto Sans Mende Kikakui, Noto Sans Miao, Noto Sans Modi, Noto Sans Mongolian, Noto Sans Mro, Noto Sans Multani, Noto Sans Newa, Noto Sans New Tai Lue, Noto Sans NKo, Noto Sans Ol Chiki, Noto Sans Oriya, Noto Sans Osage, Noto Sans Osmanya, Noto Sans Pahawh Hmong, Noto Sans Pau Cin Hau, Noto Sans Rejang, Noto Sans Runic, Noto Sans Samaritan, Noto Sans Saurashtra, Noto Sans Sharada, Noto Sans Shavian, Noto Sans Sinhala, Noto Sans Sora Sompeng, Noto Sans Soyombo, Noto Sans Sundanese, Noto Sans Syloti Nagri, Noto Sans Symbols 2, Noto Sans Symbols, Noto Sans Syriac, Noto Sans Tagalog, Noto Sans Tagbanwa, Noto Sans Tai Le, Noto Sans Tai Tham, Noto Sans Tai Viet, Noto Sans Takri, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Tifinagh Adrar, Noto Sans Tifinagh Agraw Imazighen, Noto Sans Tifinagh Ahaggar, Noto Sans Tifinagh Air, Noto Sans Tifinagh APT, Noto Sans Tifinagh Azawagh, Noto Sans Tifinagh Ghat, Noto Sans Tifinagh Hawad, Noto Sans Tifinagh, Noto Sans Tifinagh Rhissa Ixa, Noto Sans Tifinagh SIL, Noto Sans Tifinagh Tawellemmet, Noto Sans Tirhuta, Noto Sans Vai, Noto Sans Wancho, Noto Sans Warang Citi, Noto Sans Yi, Noto Sans Zanabazar Square, Noto Serif Balinese, Noto Serif Bengali, Noto Serif Devanagari, Noto Serif Dogra, Noto Serif Ethiopic, Noto Serif Georgian, Noto Serif Grantha, Noto Serif Gujarati, Noto Serif Gurmukhi, Noto Serif Kannada, Noto Serif Khmer, Noto Serif Khojki, Noto Serif Lao, Noto Serif Malayalam, Noto Serif Myanmar, Noto Serif NP Hmong, Noto Serif Sinhala, Noto Serif Tamil, Noto Serif Telugu, Noto Serif Tibetan, Noto Serif Yezidi, Noto Naskh Arabic, Noto Sans, Noto Serif, Pyidaungsu, Twemoji Mozilla"); +pref("font.name-list.emoji", "Noto Color Emoji, Twemoji Mozilla"); // Arabic pref("font.name-list.serif.ar", "Times New Roman, Noto Naskh Arabic"); pref("font.name-list.sans-serif.ar", "Segoe UI, Tahoma, Arial, Noto Naskh Arabic"); @@ -960,8 +961,9 @@ pref("font.name-list.monospace.x-unicode", "Consolas, Noto Sans Balinese, Noto S #endif #ifdef XP_LINUX -pref("font.system.whitelist", "Arimo, Cousine, Noto Naskh Arabic, Noto Sans Adlam, Noto Sans Armenian, Noto Sans Balinese, Noto Sans Bamum, Noto Sans Bassa Vah, Noto Sans Batak, Noto Sans Bengali, Noto Sans Buginese, Noto Sans Buhid, Noto Sans Canadian Aboriginal, Noto Sans Chakma, Noto Sans Cham, Noto Sans Cherokee, Noto Sans Coptic, Noto Sans Deseret, Noto Sans Devanagari, Noto Sans Elbasan, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Grantha, Noto Sans Gujarati, Noto Sans Gunjala Gondi, Noto Sans Gurmukhi, Noto Sans Hanifi Rohingya, Noto Sans Hanunoo, Noto Sans Hebrew, Noto Sans JP, Noto Sans Javanese, Noto Sans KR, Noto Sans Kannada, Noto Sans Kayah Li, Noto Sans Khmer, Noto Sans Khojki, Noto Sans Khudawadi, Noto Sans Lao, Noto Sans Lepcha, Noto Sans Limbu, Noto Sans Lisu, Noto Sans Mahajani, Noto Sans Malayalam, Noto Sans Mandaic, Noto Sans Masaram Gondi, Noto Sans Medefaidrin, Noto Sans Meetei Mayek, Noto Sans Mende Kikakui, Noto Sans Miao, Noto Sans Modi, Noto Sans Mongolian, Noto Sans Mro, Noto Sans Multani, Noto Sans NKo, Noto Sans New Tai Lue, Noto Sans Newa, Noto Sans Ol Chiki, Noto Sans Oriya, Noto Sans Osage, Noto Sans Osmanya, Noto Sans Pahawh Hmong, Noto Sans Pau Cin Hau, Noto Sans Rejang, Noto Sans Runic, Noto Sans SC, Noto Sans Samaritan, Noto Sans Saurashtra, Noto Sans Sharada, Noto Sans Shavian, Noto Sans Sinhala, Noto Sans Sora Sompeng, Noto Sans Soyombo, Noto Sans Sundanese, Noto Sans Syloti Nagri, Noto Sans Symbols, Noto Sans Symbols 2, Noto Sans Syriac, Noto Sans TC, Noto Sans Tagalog, Noto Sans Tagbanwa, Noto Sans Tai Le, Noto Sans Tai Tham, Noto Sans Tai Viet, Noto Sans Takri, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tifinagh, Noto Sans Tifinagh APT, Noto Sans Tifinagh Adrar, Noto Sans Tifinagh Agraw Imazighen, Noto Sans Tifinagh Ahaggar, Noto Sans Tifinagh Air, Noto Sans Tifinagh Azawagh, Noto Sans Tifinagh Ghat, Noto Sans Tifinagh Hawad, Noto Sans Tifinagh Rhissa Ixa, Noto Sans Tifinagh SIL, Noto Sans Tifinagh Tawellemmet, Noto Sans Tirhuta, Noto Sans Vai, Noto Sans Wancho, Noto Sans Warang Citi, Noto Sans Yi, Noto Sans Zanabazar Square, Noto Serif Armenian, Noto Serif Balinese, Noto Serif Bengali, Noto Serif Devanagari, Noto Serif Dogra, Noto Serif Ethiopic, Noto Serif Georgian, Noto Serif Grantha, Noto Serif Gujarati, Noto Serif Gurmukhi, Noto Serif Hebrew, Noto Serif Kannada, Noto Serif Khmer, Noto Serif Khojki, Noto Serif Lao, Noto Serif Malayalam, Noto Serif Myanmar, Noto Serif NP Hmong, Noto Serif Sinhala, Noto Serif Tamil, Noto Serif Telugu, Noto Serif Thai, Noto Serif Tibetan, Noto Serif Yezidi, Pyidaungsu, STIX Two Math, Tinos, Twemoji Mozilla"); +pref("font.system.whitelist", "Arimo, Cousine, Noto Color Emoji, Noto Naskh Arabic, Noto Sans Adlam, Noto Sans Armenian, Noto Sans Balinese, Noto Sans Bamum, Noto Sans Bassa Vah, Noto Sans Batak, Noto Sans Bengali, Noto Sans Buginese, Noto Sans Buhid, Noto Sans Canadian Aboriginal, Noto Sans Chakma, Noto Sans Cham, Noto Sans Cherokee, Noto Sans Coptic, Noto Sans Deseret, Noto Sans Devanagari, Noto Sans Elbasan, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Grantha, Noto Sans Gujarati, Noto Sans Gunjala Gondi, Noto Sans Gurmukhi, Noto Sans Hanifi Rohingya, Noto Sans Hanunoo, Noto Sans Hebrew, Noto Sans JP, Noto Sans Javanese, Noto Sans KR, Noto Sans Kannada, Noto Sans Kayah Li, Noto Sans Khmer, Noto Sans Khojki, Noto Sans Khudawadi, Noto Sans Lao, Noto Sans Lepcha, Noto Sans Limbu, Noto Sans Lisu, Noto Sans Mahajani, Noto Sans Malayalam, Noto Sans Mandaic, Noto Sans Masaram Gondi, Noto Sans Medefaidrin, Noto Sans Meetei Mayek, Noto Sans Mende Kikakui, Noto Sans Miao, Noto Sans Modi, Noto Sans Mongolian, Noto Sans Mro, Noto Sans Multani, Noto Sans NKo, Noto Sans New Tai Lue, Noto Sans Newa, Noto Sans Ol Chiki, Noto Sans Oriya, Noto Sans Osage, Noto Sans Osmanya, Noto Sans Pahawh Hmong, Noto Sans Pau Cin Hau, Noto Sans Rejang, Noto Sans Runic, Noto Sans SC, Noto Sans Samaritan, Noto Sans Saurashtra, Noto Sans Sharada, Noto Sans Shavian, Noto Sans Sinhala, Noto Sans Sora Sompeng, Noto Sans Soyombo, Noto Sans Sundanese, Noto Sans Syloti Nagri, Noto Sans Symbols, Noto Sans Symbols 2, Noto Sans Syriac, Noto Sans TC, Noto Sans Tagalog, Noto Sans Tagbanwa, Noto Sans Tai Le, Noto Sans Tai Tham, Noto Sans Tai Viet, Noto Sans Takri, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tifinagh, Noto Sans Tifinagh APT, Noto Sans Tifinagh Adrar, Noto Sans Tifinagh Agraw Imazighen, Noto Sans Tifinagh Ahaggar, Noto Sans Tifinagh Air, Noto Sans Tifinagh Azawagh, Noto Sans Tifinagh Ghat, Noto Sans Tifinagh Hawad, Noto Sans Tifinagh Rhissa Ixa, Noto Sans Tifinagh SIL, Noto Sans Tifinagh Tawellemmet, Noto Sans Tirhuta, Noto Sans Vai, Noto Sans Wancho, Noto Sans Warang Citi, Noto Sans Yi, Noto Sans Zanabazar Square, Noto Serif Armenian, Noto Serif Balinese, Noto Serif Bengali, Noto Serif Devanagari, Noto Serif Dogra, Noto Serif Ethiopic, Noto Serif Georgian, Noto Serif Grantha, Noto Serif Gujarati, Noto Serif Gurmukhi, Noto Serif Hebrew, Noto Serif Kannada, Noto Serif Khmer, Noto Serif Khojki, Noto Serif Lao, Noto Serif Malayalam, Noto Serif Myanmar, Noto Serif NP Hmong, Noto Serif Sinhala, Noto Serif Tamil, Noto Serif Telugu, Noto Serif Thai, Noto Serif Tibetan, Noto Serif Yezidi, Pyidaungsu, STIX Two Math, Tinos, Twemoji Mozilla"); +pref("font.name-list.emoji", "Noto Color Emoji, Twemoji Mozilla"); // Arabic pref("font.name-list.serif.ar", "Noto Naskh Arabic, Tinos"); pref("font.name-list.sans-serif.ar", "Noto Naskh Arabic, Arimo"); View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/899… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/899… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][base-browser-140.2.0esr-15.0-1] fixup! Firefox preference overrides.
by Pier Angelo Vendrame (@pierov) 09 Sep '25

09 Sep '25
Pier Angelo Vendrame pushed to branch base-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser Commits: 8dcb50e7 by Pier Angelo Vendrame at 2025-09-09T15:59:25+02:00 fixup! Firefox preference overrides. BB 43959: Switch to Noto Color Emoji on Linux and Windows. It has better compatibility than Twemoji Mozilla and upstream also did it in Bug 1939359 (for Linux). We don't use Segoe UI Emoji on Windows, so we enable Noto Color Emoji also on Windows. - - - - - 1 changed file: - browser/app/profile/001-base-profile.js Changes: ===================================== browser/app/profile/001-base-profile.js ===================================== @@ -887,8 +887,9 @@ pref("font.name-list.monospace.x-unicode", "Menlo, Courier New, Noto Sans Baline #endif #ifdef XP_WIN -pref("font.system.whitelist", "Arial, Cambria Math, Consolas, Courier New, Georgia, Lucida Console, MS Gothic, MS ゴシック, MS PGothic, MS Pゴシック, MV Boli, Malgun Gothic, Microsoft Himalaya, Microsoft JhengHei, Microsoft YaHei, 微软雅黑, Segoe UI, SimSun, 宋体, Sylfaen, Tahoma, Times New Roman, Verdana, Twemoji Mozilla, Noto Sans Adlam, Noto Sans Balinese, Noto Sans Bamum, Noto Sans Bassa Vah, Noto Sans Batak, Noto Sans Bengali, Noto Sans Buginese, Noto Sans Buhid, Noto Sans Canadian Aboriginal, Noto Sans Chakma, Noto Sans Cham, Noto Sans Cherokee, Noto Sans Coptic, Noto Sans Deseret, Noto Sans Devanagari, Noto Sans Elbasan, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Grantha, Noto Sans Gujarati, Noto Sans Gunjala Gondi, Noto Sans Gurmukhi, Noto Sans Hanifi Rohingya, Noto Sans Hanunoo, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Javanese, Noto Sans Kayah Li, Noto Sans Khojki, Noto Sans Khudawadi, Noto Sans Lao, Noto Sans Lepcha, Noto Sans Limbu, Noto Sans Lisu, Noto Sans Mahajani, Noto Sans Malayalam, Noto Sans Mandaic, Noto Sans Masaram Gondi, Noto Sans Medefaidrin, Noto Sans Meetei Mayek, Noto Sans Mende Kikakui, Noto Sans Miao, Noto Sans Modi, Noto Sans Mongolian, Noto Sans Mro, Noto Sans Multani, Noto Sans Newa, Noto Sans New Tai Lue, Noto Sans NKo, Noto Sans Ol Chiki, Noto Sans Oriya, Noto Sans Osage, Noto Sans Osmanya, Noto Sans Pahawh Hmong, Noto Sans Pau Cin Hau, Noto Sans Rejang, Noto Sans Runic, Noto Sans Samaritan, Noto Sans Saurashtra, Noto Sans Sharada, Noto Sans Shavian, Noto Sans Sinhala, Noto Sans Sora Sompeng, Noto Sans Soyombo, Noto Sans Sundanese, Noto Sans Syloti Nagri, Noto Sans Symbols 2, Noto Sans Symbols, Noto Sans Syriac, Noto Sans Tagalog, Noto Sans Tagbanwa, Noto Sans Tai Le, Noto Sans Tai Tham, Noto Sans Tai Viet, Noto Sans Takri, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Tifinagh Adrar, Noto Sans Tifinagh Agraw Imazighen, Noto Sans Tifinagh Ahaggar, Noto Sans Tifinagh Air, Noto Sans Tifinagh APT, Noto Sans Tifinagh Azawagh, Noto Sans Tifinagh Ghat, Noto Sans Tifinagh Hawad, Noto Sans Tifinagh, Noto Sans Tifinagh Rhissa Ixa, Noto Sans Tifinagh SIL, Noto Sans Tifinagh Tawellemmet, Noto Sans Tirhuta, Noto Sans Vai, Noto Sans Wancho, Noto Sans Warang Citi, Noto Sans Yi, Noto Sans Zanabazar Square, Noto Serif Balinese, Noto Serif Bengali, Noto Serif Devanagari, Noto Serif Dogra, Noto Serif Ethiopic, Noto Serif Georgian, Noto Serif Grantha, Noto Serif Gujarati, Noto Serif Gurmukhi, Noto Serif Kannada, Noto Serif Khmer, Noto Serif Khojki, Noto Serif Lao, Noto Serif Malayalam, Noto Serif Myanmar, Noto Serif NP Hmong, Noto Serif Sinhala, Noto Serif Tamil, Noto Serif Telugu, Noto Serif Tibetan, Noto Serif Yezidi, Noto Naskh Arabic, Noto Sans, Noto Serif, Pyidaungsu"); +pref("font.system.whitelist", "Arial, Cambria Math, Consolas, Courier New, Georgia, Lucida Console, MS Gothic, MS ゴシック, MS PGothic, MS Pゴシック, MV Boli, Malgun Gothic, Microsoft Himalaya, Microsoft JhengHei, Microsoft YaHei, 微软雅黑, Segoe UI, SimSun, 宋体, Sylfaen, Tahoma, Times New Roman, Verdana, Noto Color Emoji, Noto Sans Adlam, Noto Sans Balinese, Noto Sans Bamum, Noto Sans Bassa Vah, Noto Sans Batak, Noto Sans Bengali, Noto Sans Buginese, Noto Sans Buhid, Noto Sans Canadian Aboriginal, Noto Sans Chakma, Noto Sans Cham, Noto Sans Cherokee, Noto Sans Coptic, Noto Sans Deseret, Noto Sans Devanagari, Noto Sans Elbasan, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Grantha, Noto Sans Gujarati, Noto Sans Gunjala Gondi, Noto Sans Gurmukhi, Noto Sans Hanifi Rohingya, Noto Sans Hanunoo, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Javanese, Noto Sans Kayah Li, Noto Sans Khojki, Noto Sans Khudawadi, Noto Sans Lao, Noto Sans Lepcha, Noto Sans Limbu, Noto Sans Lisu, Noto Sans Mahajani, Noto Sans Malayalam, Noto Sans Mandaic, Noto Sans Masaram Gondi, Noto Sans Medefaidrin, Noto Sans Meetei Mayek, Noto Sans Mende Kikakui, Noto Sans Miao, Noto Sans Modi, Noto Sans Mongolian, Noto Sans Mro, Noto Sans Multani, Noto Sans Newa, Noto Sans New Tai Lue, Noto Sans NKo, Noto Sans Ol Chiki, Noto Sans Oriya, Noto Sans Osage, Noto Sans Osmanya, Noto Sans Pahawh Hmong, Noto Sans Pau Cin Hau, Noto Sans Rejang, Noto Sans Runic, Noto Sans Samaritan, Noto Sans Saurashtra, Noto Sans Sharada, Noto Sans Shavian, Noto Sans Sinhala, Noto Sans Sora Sompeng, Noto Sans Soyombo, Noto Sans Sundanese, Noto Sans Syloti Nagri, Noto Sans Symbols 2, Noto Sans Symbols, Noto Sans Syriac, Noto Sans Tagalog, Noto Sans Tagbanwa, Noto Sans Tai Le, Noto Sans Tai Tham, Noto Sans Tai Viet, Noto Sans Takri, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Tifinagh Adrar, Noto Sans Tifinagh Agraw Imazighen, Noto Sans Tifinagh Ahaggar, Noto Sans Tifinagh Air, Noto Sans Tifinagh APT, Noto Sans Tifinagh Azawagh, Noto Sans Tifinagh Ghat, Noto Sans Tifinagh Hawad, Noto Sans Tifinagh, Noto Sans Tifinagh Rhissa Ixa, Noto Sans Tifinagh SIL, Noto Sans Tifinagh Tawellemmet, Noto Sans Tirhuta, Noto Sans Vai, Noto Sans Wancho, Noto Sans Warang Citi, Noto Sans Yi, Noto Sans Zanabazar Square, Noto Serif Balinese, Noto Serif Bengali, Noto Serif Devanagari, Noto Serif Dogra, Noto Serif Ethiopic, Noto Serif Georgian, Noto Serif Grantha, Noto Serif Gujarati, Noto Serif Gurmukhi, Noto Serif Kannada, Noto Serif Khmer, Noto Serif Khojki, Noto Serif Lao, Noto Serif Malayalam, Noto Serif Myanmar, Noto Serif NP Hmong, Noto Serif Sinhala, Noto Serif Tamil, Noto Serif Telugu, Noto Serif Tibetan, Noto Serif Yezidi, Noto Naskh Arabic, Noto Sans, Noto Serif, Pyidaungsu, Twemoji Mozilla"); +pref("font.name-list.emoji", "Noto Color Emoji, Twemoji Mozilla"); // Arabic pref("font.name-list.serif.ar", "Times New Roman, Noto Naskh Arabic"); pref("font.name-list.sans-serif.ar", "Segoe UI, Tahoma, Arial, Noto Naskh Arabic"); @@ -964,8 +965,9 @@ pref("font.name-list.monospace.x-unicode", "Consolas, Noto Sans Balinese, Noto S #endif #ifdef XP_LINUX -pref("font.system.whitelist", "Arimo, Cousine, Noto Naskh Arabic, Noto Sans Adlam, Noto Sans Armenian, Noto Sans Balinese, Noto Sans Bamum, Noto Sans Bassa Vah, Noto Sans Batak, Noto Sans Bengali, Noto Sans Buginese, Noto Sans Buhid, Noto Sans Canadian Aboriginal, Noto Sans Chakma, Noto Sans Cham, Noto Sans Cherokee, Noto Sans Coptic, Noto Sans Deseret, Noto Sans Devanagari, Noto Sans Elbasan, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Grantha, Noto Sans Gujarati, Noto Sans Gunjala Gondi, Noto Sans Gurmukhi, Noto Sans Hanifi Rohingya, Noto Sans Hanunoo, Noto Sans Hebrew, Noto Sans JP, Noto Sans Javanese, Noto Sans KR, Noto Sans Kannada, Noto Sans Kayah Li, Noto Sans Khmer, Noto Sans Khojki, Noto Sans Khudawadi, Noto Sans Lao, Noto Sans Lepcha, Noto Sans Limbu, Noto Sans Lisu, Noto Sans Mahajani, Noto Sans Malayalam, Noto Sans Mandaic, Noto Sans Masaram Gondi, Noto Sans Medefaidrin, Noto Sans Meetei Mayek, Noto Sans Mende Kikakui, Noto Sans Miao, Noto Sans Modi, Noto Sans Mongolian, Noto Sans Mro, Noto Sans Multani, Noto Sans NKo, Noto Sans New Tai Lue, Noto Sans Newa, Noto Sans Ol Chiki, Noto Sans Oriya, Noto Sans Osage, Noto Sans Osmanya, Noto Sans Pahawh Hmong, Noto Sans Pau Cin Hau, Noto Sans Rejang, Noto Sans Runic, Noto Sans SC, Noto Sans Samaritan, Noto Sans Saurashtra, Noto Sans Sharada, Noto Sans Shavian, Noto Sans Sinhala, Noto Sans Sora Sompeng, Noto Sans Soyombo, Noto Sans Sundanese, Noto Sans Syloti Nagri, Noto Sans Symbols, Noto Sans Symbols 2, Noto Sans Syriac, Noto Sans TC, Noto Sans Tagalog, Noto Sans Tagbanwa, Noto Sans Tai Le, Noto Sans Tai Tham, Noto Sans Tai Viet, Noto Sans Takri, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tifinagh, Noto Sans Tifinagh APT, Noto Sans Tifinagh Adrar, Noto Sans Tifinagh Agraw Imazighen, Noto Sans Tifinagh Ahaggar, Noto Sans Tifinagh Air, Noto Sans Tifinagh Azawagh, Noto Sans Tifinagh Ghat, Noto Sans Tifinagh Hawad, Noto Sans Tifinagh Rhissa Ixa, Noto Sans Tifinagh SIL, Noto Sans Tifinagh Tawellemmet, Noto Sans Tirhuta, Noto Sans Vai, Noto Sans Wancho, Noto Sans Warang Citi, Noto Sans Yi, Noto Sans Zanabazar Square, Noto Serif Armenian, Noto Serif Balinese, Noto Serif Bengali, Noto Serif Devanagari, Noto Serif Dogra, Noto Serif Ethiopic, Noto Serif Georgian, Noto Serif Grantha, Noto Serif Gujarati, Noto Serif Gurmukhi, Noto Serif Hebrew, Noto Serif Kannada, Noto Serif Khmer, Noto Serif Khojki, Noto Serif Lao, Noto Serif Malayalam, Noto Serif Myanmar, Noto Serif NP Hmong, Noto Serif Sinhala, Noto Serif Tamil, Noto Serif Telugu, Noto Serif Thai, Noto Serif Tibetan, Noto Serif Yezidi, Pyidaungsu, STIX Two Math, Tinos, Twemoji Mozilla"); +pref("font.system.whitelist", "Arimo, Cousine, Noto Color Emoji, Noto Naskh Arabic, Noto Sans Adlam, Noto Sans Armenian, Noto Sans Balinese, Noto Sans Bamum, Noto Sans Bassa Vah, Noto Sans Batak, Noto Sans Bengali, Noto Sans Buginese, Noto Sans Buhid, Noto Sans Canadian Aboriginal, Noto Sans Chakma, Noto Sans Cham, Noto Sans Cherokee, Noto Sans Coptic, Noto Sans Deseret, Noto Sans Devanagari, Noto Sans Elbasan, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Grantha, Noto Sans Gujarati, Noto Sans Gunjala Gondi, Noto Sans Gurmukhi, Noto Sans Hanifi Rohingya, Noto Sans Hanunoo, Noto Sans Hebrew, Noto Sans JP, Noto Sans Javanese, Noto Sans KR, Noto Sans Kannada, Noto Sans Kayah Li, Noto Sans Khmer, Noto Sans Khojki, Noto Sans Khudawadi, Noto Sans Lao, Noto Sans Lepcha, Noto Sans Limbu, Noto Sans Lisu, Noto Sans Mahajani, Noto Sans Malayalam, Noto Sans Mandaic, Noto Sans Masaram Gondi, Noto Sans Medefaidrin, Noto Sans Meetei Mayek, Noto Sans Mende Kikakui, Noto Sans Miao, Noto Sans Modi, Noto Sans Mongolian, Noto Sans Mro, Noto Sans Multani, Noto Sans NKo, Noto Sans New Tai Lue, Noto Sans Newa, Noto Sans Ol Chiki, Noto Sans Oriya, Noto Sans Osage, Noto Sans Osmanya, Noto Sans Pahawh Hmong, Noto Sans Pau Cin Hau, Noto Sans Rejang, Noto Sans Runic, Noto Sans SC, Noto Sans Samaritan, Noto Sans Saurashtra, Noto Sans Sharada, Noto Sans Shavian, Noto Sans Sinhala, Noto Sans Sora Sompeng, Noto Sans Soyombo, Noto Sans Sundanese, Noto Sans Syloti Nagri, Noto Sans Symbols, Noto Sans Symbols 2, Noto Sans Syriac, Noto Sans TC, Noto Sans Tagalog, Noto Sans Tagbanwa, Noto Sans Tai Le, Noto Sans Tai Tham, Noto Sans Tai Viet, Noto Sans Takri, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tifinagh, Noto Sans Tifinagh APT, Noto Sans Tifinagh Adrar, Noto Sans Tifinagh Agraw Imazighen, Noto Sans Tifinagh Ahaggar, Noto Sans Tifinagh Air, Noto Sans Tifinagh Azawagh, Noto Sans Tifinagh Ghat, Noto Sans Tifinagh Hawad, Noto Sans Tifinagh Rhissa Ixa, Noto Sans Tifinagh SIL, Noto Sans Tifinagh Tawellemmet, Noto Sans Tirhuta, Noto Sans Vai, Noto Sans Wancho, Noto Sans Warang Citi, Noto Sans Yi, Noto Sans Zanabazar Square, Noto Serif Armenian, Noto Serif Balinese, Noto Serif Bengali, Noto Serif Devanagari, Noto Serif Dogra, Noto Serif Ethiopic, Noto Serif Georgian, Noto Serif Grantha, Noto Serif Gujarati, Noto Serif Gurmukhi, Noto Serif Hebrew, Noto Serif Kannada, Noto Serif Khmer, Noto Serif Khojki, Noto Serif Lao, Noto Serif Malayalam, Noto Serif Myanmar, Noto Serif NP Hmong, Noto Serif Sinhala, Noto Serif Tamil, Noto Serif Telugu, Noto Serif Thai, Noto Serif Tibetan, Noto Serif Yezidi, Pyidaungsu, STIX Two Math, Tinos, Twemoji Mozilla"); +pref("font.name-list.emoji", "Noto Color Emoji, Twemoji Mozilla"); // Arabic pref("font.name-list.serif.ar", "Noto Naskh Arabic, Tinos"); pref("font.name-list.sans-serif.ar", "Noto Naskh Arabic, Arimo"); View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/8dcb50e… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/8dcb50e… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][tor-browser-140.2.0esr-15.0-1] fixup! Firefox preference overrides.
by Pier Angelo Vendrame (@pierov) 09 Sep '25

09 Sep '25
Pier Angelo Vendrame pushed to branch tor-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser Commits: 8cf95921 by Pier Angelo Vendrame at 2025-09-09T15:58:27+02:00 fixup! Firefox preference overrides. BB 43959: Switch to Noto Color Emoji on Linux and Windows. It has better compatibility than Twemoji Mozilla and upstream also did it in Bug 1939359 (for Linux). We don't use Segoe UI Emoji on Windows, so we enable Noto Color Emoji also on Windows. - - - - - 1 changed file: - browser/app/profile/001-base-profile.js Changes: ===================================== browser/app/profile/001-base-profile.js ===================================== @@ -887,8 +887,9 @@ pref("font.name-list.monospace.x-unicode", "Menlo, Courier New, Noto Sans Baline #endif #ifdef XP_WIN -pref("font.system.whitelist", "Arial, Cambria Math, Consolas, Courier New, Georgia, Lucida Console, MS Gothic, MS ゴシック, MS PGothic, MS Pゴシック, MV Boli, Malgun Gothic, Microsoft Himalaya, Microsoft JhengHei, Microsoft YaHei, 微软雅黑, Segoe UI, SimSun, 宋体, Sylfaen, Tahoma, Times New Roman, Verdana, Twemoji Mozilla, Noto Sans Adlam, Noto Sans Balinese, Noto Sans Bamum, Noto Sans Bassa Vah, Noto Sans Batak, Noto Sans Bengali, Noto Sans Buginese, Noto Sans Buhid, Noto Sans Canadian Aboriginal, Noto Sans Chakma, Noto Sans Cham, Noto Sans Cherokee, Noto Sans Coptic, Noto Sans Deseret, Noto Sans Devanagari, Noto Sans Elbasan, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Grantha, Noto Sans Gujarati, Noto Sans Gunjala Gondi, Noto Sans Gurmukhi, Noto Sans Hanifi Rohingya, Noto Sans Hanunoo, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Javanese, Noto Sans Kayah Li, Noto Sans Khojki, Noto Sans Khudawadi, Noto Sans Lao, Noto Sans Lepcha, Noto Sans Limbu, Noto Sans Lisu, Noto Sans Mahajani, Noto Sans Malayalam, Noto Sans Mandaic, Noto Sans Masaram Gondi, Noto Sans Medefaidrin, Noto Sans Meetei Mayek, Noto Sans Mende Kikakui, Noto Sans Miao, Noto Sans Modi, Noto Sans Mongolian, Noto Sans Mro, Noto Sans Multani, Noto Sans Newa, Noto Sans New Tai Lue, Noto Sans NKo, Noto Sans Ol Chiki, Noto Sans Oriya, Noto Sans Osage, Noto Sans Osmanya, Noto Sans Pahawh Hmong, Noto Sans Pau Cin Hau, Noto Sans Rejang, Noto Sans Runic, Noto Sans Samaritan, Noto Sans Saurashtra, Noto Sans Sharada, Noto Sans Shavian, Noto Sans Sinhala, Noto Sans Sora Sompeng, Noto Sans Soyombo, Noto Sans Sundanese, Noto Sans Syloti Nagri, Noto Sans Symbols 2, Noto Sans Symbols, Noto Sans Syriac, Noto Sans Tagalog, Noto Sans Tagbanwa, Noto Sans Tai Le, Noto Sans Tai Tham, Noto Sans Tai Viet, Noto Sans Takri, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Tifinagh Adrar, Noto Sans Tifinagh Agraw Imazighen, Noto Sans Tifinagh Ahaggar, Noto Sans Tifinagh Air, Noto Sans Tifinagh APT, Noto Sans Tifinagh Azawagh, Noto Sans Tifinagh Ghat, Noto Sans Tifinagh Hawad, Noto Sans Tifinagh, Noto Sans Tifinagh Rhissa Ixa, Noto Sans Tifinagh SIL, Noto Sans Tifinagh Tawellemmet, Noto Sans Tirhuta, Noto Sans Vai, Noto Sans Wancho, Noto Sans Warang Citi, Noto Sans Yi, Noto Sans Zanabazar Square, Noto Serif Balinese, Noto Serif Bengali, Noto Serif Devanagari, Noto Serif Dogra, Noto Serif Ethiopic, Noto Serif Georgian, Noto Serif Grantha, Noto Serif Gujarati, Noto Serif Gurmukhi, Noto Serif Kannada, Noto Serif Khmer, Noto Serif Khojki, Noto Serif Lao, Noto Serif Malayalam, Noto Serif Myanmar, Noto Serif NP Hmong, Noto Serif Sinhala, Noto Serif Tamil, Noto Serif Telugu, Noto Serif Tibetan, Noto Serif Yezidi, Noto Naskh Arabic, Noto Sans, Noto Serif, Pyidaungsu"); +pref("font.system.whitelist", "Arial, Cambria Math, Consolas, Courier New, Georgia, Lucida Console, MS Gothic, MS ゴシック, MS PGothic, MS Pゴシック, MV Boli, Malgun Gothic, Microsoft Himalaya, Microsoft JhengHei, Microsoft YaHei, 微软雅黑, Segoe UI, SimSun, 宋体, Sylfaen, Tahoma, Times New Roman, Verdana, Noto Color Emoji, Noto Sans Adlam, Noto Sans Balinese, Noto Sans Bamum, Noto Sans Bassa Vah, Noto Sans Batak, Noto Sans Bengali, Noto Sans Buginese, Noto Sans Buhid, Noto Sans Canadian Aboriginal, Noto Sans Chakma, Noto Sans Cham, Noto Sans Cherokee, Noto Sans Coptic, Noto Sans Deseret, Noto Sans Devanagari, Noto Sans Elbasan, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Grantha, Noto Sans Gujarati, Noto Sans Gunjala Gondi, Noto Sans Gurmukhi, Noto Sans Hanifi Rohingya, Noto Sans Hanunoo, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Javanese, Noto Sans Kayah Li, Noto Sans Khojki, Noto Sans Khudawadi, Noto Sans Lao, Noto Sans Lepcha, Noto Sans Limbu, Noto Sans Lisu, Noto Sans Mahajani, Noto Sans Malayalam, Noto Sans Mandaic, Noto Sans Masaram Gondi, Noto Sans Medefaidrin, Noto Sans Meetei Mayek, Noto Sans Mende Kikakui, Noto Sans Miao, Noto Sans Modi, Noto Sans Mongolian, Noto Sans Mro, Noto Sans Multani, Noto Sans Newa, Noto Sans New Tai Lue, Noto Sans NKo, Noto Sans Ol Chiki, Noto Sans Oriya, Noto Sans Osage, Noto Sans Osmanya, Noto Sans Pahawh Hmong, Noto Sans Pau Cin Hau, Noto Sans Rejang, Noto Sans Runic, Noto Sans Samaritan, Noto Sans Saurashtra, Noto Sans Sharada, Noto Sans Shavian, Noto Sans Sinhala, Noto Sans Sora Sompeng, Noto Sans Soyombo, Noto Sans Sundanese, Noto Sans Syloti Nagri, Noto Sans Symbols 2, Noto Sans Symbols, Noto Sans Syriac, Noto Sans Tagalog, Noto Sans Tagbanwa, Noto Sans Tai Le, Noto Sans Tai Tham, Noto Sans Tai Viet, Noto Sans Takri, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Tifinagh Adrar, Noto Sans Tifinagh Agraw Imazighen, Noto Sans Tifinagh Ahaggar, Noto Sans Tifinagh Air, Noto Sans Tifinagh APT, Noto Sans Tifinagh Azawagh, Noto Sans Tifinagh Ghat, Noto Sans Tifinagh Hawad, Noto Sans Tifinagh, Noto Sans Tifinagh Rhissa Ixa, Noto Sans Tifinagh SIL, Noto Sans Tifinagh Tawellemmet, Noto Sans Tirhuta, Noto Sans Vai, Noto Sans Wancho, Noto Sans Warang Citi, Noto Sans Yi, Noto Sans Zanabazar Square, Noto Serif Balinese, Noto Serif Bengali, Noto Serif Devanagari, Noto Serif Dogra, Noto Serif Ethiopic, Noto Serif Georgian, Noto Serif Grantha, Noto Serif Gujarati, Noto Serif Gurmukhi, Noto Serif Kannada, Noto Serif Khmer, Noto Serif Khojki, Noto Serif Lao, Noto Serif Malayalam, Noto Serif Myanmar, Noto Serif NP Hmong, Noto Serif Sinhala, Noto Serif Tamil, Noto Serif Telugu, Noto Serif Tibetan, Noto Serif Yezidi, Noto Naskh Arabic, Noto Sans, Noto Serif, Pyidaungsu, Twemoji Mozilla"); +pref("font.name-list.emoji", "Noto Color Emoji, Twemoji Mozilla"); // Arabic pref("font.name-list.serif.ar", "Times New Roman, Noto Naskh Arabic"); pref("font.name-list.sans-serif.ar", "Segoe UI, Tahoma, Arial, Noto Naskh Arabic"); @@ -964,8 +965,9 @@ pref("font.name-list.monospace.x-unicode", "Consolas, Noto Sans Balinese, Noto S #endif #ifdef XP_LINUX -pref("font.system.whitelist", "Arimo, Cousine, Noto Naskh Arabic, Noto Sans Adlam, Noto Sans Armenian, Noto Sans Balinese, Noto Sans Bamum, Noto Sans Bassa Vah, Noto Sans Batak, Noto Sans Bengali, Noto Sans Buginese, Noto Sans Buhid, Noto Sans Canadian Aboriginal, Noto Sans Chakma, Noto Sans Cham, Noto Sans Cherokee, Noto Sans Coptic, Noto Sans Deseret, Noto Sans Devanagari, Noto Sans Elbasan, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Grantha, Noto Sans Gujarati, Noto Sans Gunjala Gondi, Noto Sans Gurmukhi, Noto Sans Hanifi Rohingya, Noto Sans Hanunoo, Noto Sans Hebrew, Noto Sans JP, Noto Sans Javanese, Noto Sans KR, Noto Sans Kannada, Noto Sans Kayah Li, Noto Sans Khmer, Noto Sans Khojki, Noto Sans Khudawadi, Noto Sans Lao, Noto Sans Lepcha, Noto Sans Limbu, Noto Sans Lisu, Noto Sans Mahajani, Noto Sans Malayalam, Noto Sans Mandaic, Noto Sans Masaram Gondi, Noto Sans Medefaidrin, Noto Sans Meetei Mayek, Noto Sans Mende Kikakui, Noto Sans Miao, Noto Sans Modi, Noto Sans Mongolian, Noto Sans Mro, Noto Sans Multani, Noto Sans NKo, Noto Sans New Tai Lue, Noto Sans Newa, Noto Sans Ol Chiki, Noto Sans Oriya, Noto Sans Osage, Noto Sans Osmanya, Noto Sans Pahawh Hmong, Noto Sans Pau Cin Hau, Noto Sans Rejang, Noto Sans Runic, Noto Sans SC, Noto Sans Samaritan, Noto Sans Saurashtra, Noto Sans Sharada, Noto Sans Shavian, Noto Sans Sinhala, Noto Sans Sora Sompeng, Noto Sans Soyombo, Noto Sans Sundanese, Noto Sans Syloti Nagri, Noto Sans Symbols, Noto Sans Symbols 2, Noto Sans Syriac, Noto Sans TC, Noto Sans Tagalog, Noto Sans Tagbanwa, Noto Sans Tai Le, Noto Sans Tai Tham, Noto Sans Tai Viet, Noto Sans Takri, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tifinagh, Noto Sans Tifinagh APT, Noto Sans Tifinagh Adrar, Noto Sans Tifinagh Agraw Imazighen, Noto Sans Tifinagh Ahaggar, Noto Sans Tifinagh Air, Noto Sans Tifinagh Azawagh, Noto Sans Tifinagh Ghat, Noto Sans Tifinagh Hawad, Noto Sans Tifinagh Rhissa Ixa, Noto Sans Tifinagh SIL, Noto Sans Tifinagh Tawellemmet, Noto Sans Tirhuta, Noto Sans Vai, Noto Sans Wancho, Noto Sans Warang Citi, Noto Sans Yi, Noto Sans Zanabazar Square, Noto Serif Armenian, Noto Serif Balinese, Noto Serif Bengali, Noto Serif Devanagari, Noto Serif Dogra, Noto Serif Ethiopic, Noto Serif Georgian, Noto Serif Grantha, Noto Serif Gujarati, Noto Serif Gurmukhi, Noto Serif Hebrew, Noto Serif Kannada, Noto Serif Khmer, Noto Serif Khojki, Noto Serif Lao, Noto Serif Malayalam, Noto Serif Myanmar, Noto Serif NP Hmong, Noto Serif Sinhala, Noto Serif Tamil, Noto Serif Telugu, Noto Serif Thai, Noto Serif Tibetan, Noto Serif Yezidi, Pyidaungsu, STIX Two Math, Tinos, Twemoji Mozilla"); +pref("font.system.whitelist", "Arimo, Cousine, Noto Color Emoji, Noto Naskh Arabic, Noto Sans Adlam, Noto Sans Armenian, Noto Sans Balinese, Noto Sans Bamum, Noto Sans Bassa Vah, Noto Sans Batak, Noto Sans Bengali, Noto Sans Buginese, Noto Sans Buhid, Noto Sans Canadian Aboriginal, Noto Sans Chakma, Noto Sans Cham, Noto Sans Cherokee, Noto Sans Coptic, Noto Sans Deseret, Noto Sans Devanagari, Noto Sans Elbasan, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Grantha, Noto Sans Gujarati, Noto Sans Gunjala Gondi, Noto Sans Gurmukhi, Noto Sans Hanifi Rohingya, Noto Sans Hanunoo, Noto Sans Hebrew, Noto Sans JP, Noto Sans Javanese, Noto Sans KR, Noto Sans Kannada, Noto Sans Kayah Li, Noto Sans Khmer, Noto Sans Khojki, Noto Sans Khudawadi, Noto Sans Lao, Noto Sans Lepcha, Noto Sans Limbu, Noto Sans Lisu, Noto Sans Mahajani, Noto Sans Malayalam, Noto Sans Mandaic, Noto Sans Masaram Gondi, Noto Sans Medefaidrin, Noto Sans Meetei Mayek, Noto Sans Mende Kikakui, Noto Sans Miao, Noto Sans Modi, Noto Sans Mongolian, Noto Sans Mro, Noto Sans Multani, Noto Sans NKo, Noto Sans New Tai Lue, Noto Sans Newa, Noto Sans Ol Chiki, Noto Sans Oriya, Noto Sans Osage, Noto Sans Osmanya, Noto Sans Pahawh Hmong, Noto Sans Pau Cin Hau, Noto Sans Rejang, Noto Sans Runic, Noto Sans SC, Noto Sans Samaritan, Noto Sans Saurashtra, Noto Sans Sharada, Noto Sans Shavian, Noto Sans Sinhala, Noto Sans Sora Sompeng, Noto Sans Soyombo, Noto Sans Sundanese, Noto Sans Syloti Nagri, Noto Sans Symbols, Noto Sans Symbols 2, Noto Sans Syriac, Noto Sans TC, Noto Sans Tagalog, Noto Sans Tagbanwa, Noto Sans Tai Le, Noto Sans Tai Tham, Noto Sans Tai Viet, Noto Sans Takri, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tifinagh, Noto Sans Tifinagh APT, Noto Sans Tifinagh Adrar, Noto Sans Tifinagh Agraw Imazighen, Noto Sans Tifinagh Ahaggar, Noto Sans Tifinagh Air, Noto Sans Tifinagh Azawagh, Noto Sans Tifinagh Ghat, Noto Sans Tifinagh Hawad, Noto Sans Tifinagh Rhissa Ixa, Noto Sans Tifinagh SIL, Noto Sans Tifinagh Tawellemmet, Noto Sans Tirhuta, Noto Sans Vai, Noto Sans Wancho, Noto Sans Warang Citi, Noto Sans Yi, Noto Sans Zanabazar Square, Noto Serif Armenian, Noto Serif Balinese, Noto Serif Bengali, Noto Serif Devanagari, Noto Serif Dogra, Noto Serif Ethiopic, Noto Serif Georgian, Noto Serif Grantha, Noto Serif Gujarati, Noto Serif Gurmukhi, Noto Serif Hebrew, Noto Serif Kannada, Noto Serif Khmer, Noto Serif Khojki, Noto Serif Lao, Noto Serif Malayalam, Noto Serif Myanmar, Noto Serif NP Hmong, Noto Serif Sinhala, Noto Serif Tamil, Noto Serif Telugu, Noto Serif Thai, Noto Serif Tibetan, Noto Serif Yezidi, Pyidaungsu, STIX Two Math, Tinos, Twemoji Mozilla"); +pref("font.name-list.emoji", "Noto Color Emoji, Twemoji Mozilla"); // Arabic pref("font.name-list.serif.ar", "Noto Naskh Arabic, Tinos"); pref("font.name-list.sans-serif.ar", "Noto Naskh Arabic, Arimo"); View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/8cf9592… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/8cf9592… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser-build][main] Bug 41561: Ship Noto Color Emoji on Linux and Windows.
by Pier Angelo Vendrame (@pierov) 09 Sep '25

09 Sep '25
Pier Angelo Vendrame pushed to branch main at The Tor Project / Applications / tor-browser-build Commits: 7be3d4ea by Pier Angelo Vendrame at 2025-09-08T09:35:31+02:00 Bug 41561: Ship Noto Color Emoji on Linux and Windows. - - - - - 2 changed files: - projects/fonts/build - projects/fonts/config Changes: ===================================== projects/fonts/build ===================================== @@ -31,6 +31,10 @@ mv noto-fonts-* noto-fonts cp Arimo-*/fonts/ttf/*.ttf Cousine-* Tinos-* NotoSans{JP,KR,SC,TC}-Regular.otf $distdir/ [% END %] +[% IF c("var/linux") || c("var/windows") %] + cp NotoColorEmoji.ttf $distdir/ +[% END %] + cp "$rootdir/[% c('input_files_by_name/Pyidaungsu') %]" $distdir/ cp README.txt "$distdir/000_README.txt" ===================================== projects/fonts/config ===================================== @@ -188,6 +188,9 @@ input_files: - URL: https://github.com/googlefonts/noto-cjk/raw/523d033d6cb47f4a80c58a35753646f… sha256sum: 5bab0cb3c1cf89dde07c4a95a4054b195afbcfe784d69d75c340780712237537 enable: '[% c("var/linux") %]' + - URL: https://github.com/googlefonts/noto-emoji/raw/b3e3051a088047d19fd4d49b1c3ac… + sha256sum: 3ed77810c203e1a67735dc19d395f32c23f2d7c0c3696690f4f78e15e57ab816 + enable: '[% c("var/linux") || c("var/windows") %]' - URL: https://github.com/stipub/stixfonts/raw/v2.13b171/fonts/static_otf/STIXTwoM… sha256sum: 3a5f3f26f40d5698b3c62dd085d48d6663696a3f80825aab8b553d5097518e8c name: stix View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/7… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/7… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/mullvad-browser][mullvad-browser-140.2.0esr-15.0-1] fixup! Add CI for Base Browser
by brizental (@brizental) 09 Sep '25

09 Sep '25
brizental pushed to branch mullvad-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Mullvad Browser Commits: 081b9f68 by Beatriz Rizental at 2025-09-09T13:10:41+02:00 fixup! Add CI for Base Browser - - - - - 5 changed files: - .gitlab-ci.yml - .gitlab/ci/jobs/lint/helpers.py → .gitlab/ci/jobs/helpers.py - .gitlab/ci/jobs/lint/lint.yml - + .gitlab/ci/jobs/test/python-test.yml - .gitlab/ci/jobs/update-translations.yml Changes: ===================================== .gitlab-ci.yml ===================================== @@ -1,5 +1,6 @@ stages: - lint + - test - update-translations variables: @@ -9,4 +10,5 @@ variables: include: - local: '.gitlab/ci/mixins.yml' - local: '.gitlab/ci/jobs/lint/lint.yml' + - local: '.gitlab/ci/jobs/test/python-test.yml' - local: '.gitlab/ci/jobs/update-translations.yml' ===================================== .gitlab/ci/jobs/lint/helpers.py → .gitlab/ci/jobs/helpers.py ===================================== @@ -112,7 +112,7 @@ if __name__ == "__main__": parser.add_argument( "--get-changed-files", help="Get list of changed files." - "When running from a merge request get sthe list of changed files since the merge-base of the current branch." + "When running from a merge request gets the list of changed files since the merge-base of the current branch." "When running from a protected branch i.e. any branch that starts with <something>-browser-, gets the list of files changed since the FIREFOX_ tag.", action="store_true", ) ===================================== .gitlab/ci/jobs/lint/lint.yml ===================================== @@ -18,7 +18,7 @@ lint-all: - firefox script: - ./mach configure --with-base-browser-version=0.0.0 - - .gitlab/ci/jobs/lint/helpers.py --get-changed-files | xargs -0 --no-run-if-empty ./mach lint -v + - .gitlab/ci/jobs/helpers.py --get-changed-files | xargs -0 --no-run-if-empty ./mach lint -v rules: - if: $CI_PIPELINE_SOURCE == 'merge_request_event' # Run job whenever a commit is merged to a protected branch ===================================== .gitlab/ci/jobs/test/python-test.yml ===================================== @@ -0,0 +1,24 @@ +python-test: + extends: .with-local-repo-bash + stage: test + image: $IMAGE_PATH + interruptible: true + variables: + MOZBUILD_STATE_PATH: "/var/tmp/mozbuild" + cache: + paths: + - node_modules + # Store the cache regardless on job outcome + when: 'always' + # Share the cache throughout all pipelines running for a given branch + key: $CI_COMMIT_REF_SLUG + tags: + # Run these jobs in the browser dedicated runners. + - firefox + script: + - ./mach configure --with-base-browser-version=0.0.0 + - .gitlab/ci/jobs/helpers.py --get-changed-files | xargs -0 --no-run-if-empty ./mach python-test -v + rules: + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' || ($CI_COMMIT_BRANCH && $CI_COMMIT_REF_PROTECTED == 'true' && $CI_PIPELINE_SOURCE == 'push') + changes: + - "**/test_*.py" ===================================== .gitlab/ci/jobs/update-translations.yml ===================================== @@ -81,7 +81,7 @@ combine-en-US-translations: # push-en-US-translations job. - echo 'COMBINE_TRANSLATIONS_JOB_ID='"$CI_JOB_ID" >job_id.env - pip install compare_locales - - python ./tools/base-browser/l10n/combine-translation-versions.py "$CI_COMMIT_BRANCH" "$TRANSLATION_FILES" "$COMBINED_FILES_JSON" + - python ./tools/base_browser/l10n/combine-translation-versions.py "$CI_COMMIT_BRANCH" "$TRANSLATION_FILES" "$COMBINED_FILES_JSON" push-en-US-translations: extends: .update-translation-base View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/081… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/081… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][tor-browser-115.27.0esr-13.5-1] fixup! Bug 43125: Extend the 13.5 EOL expiry date for tor-browser.
by Pier Angelo Vendrame (@pierov) 09 Sep '25

09 Sep '25
Pier Angelo Vendrame pushed to branch tor-browser-115.27.0esr-13.5-1 at The Tor Project / Applications / Tor Browser Commits: 55d160b3 by Henry Wilkes at 2025-09-08T17:57:36+01:00 fixup! Bug 43125: Extend the 13.5 EOL expiry date for tor-browser. TB 43168: Extend the 13.5 EOL to 24th March 2026. - - - - - 1 changed file: - browser/base/content/droppedSupportNotification.js Changes: ===================================== browser/base/content/droppedSupportNotification.js ===================================== @@ -3,8 +3,8 @@ // Show a prompt that a user's system will no longer be supported. window.addEventListener("load", () => { let labelId; - // ESR 115 EOL pushed to 14th October 2025. - const isExpired = Date.now() > Date.UTC(2025, 9, 14); + // ESR 115 EOL pushed to 24th March 2026. + const isExpired = Date.now() > Date.UTC(2026, 2, 24); if ( AppConstants.platform === "macosx" && View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/55d160b… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/55d160b… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser] Pushed new tag tor-browser-143.0a1-16.0-1-build1
by brizental (@brizental) 08 Sep '25

08 Sep '25
brizental pushed new tag tor-browser-143.0a1-16.0-1-build1 at The Tor Project / Applications / Tor Browser -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/tree/tor-brows… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/mullvad-browser][mullvad-browser-140.2.0esr-15.0-1] 6 commits: BB 43564: Modify ./mach bootstrap for Base Browser
by brizental (@brizental) 08 Sep '25

08 Sep '25
brizental pushed to branch mullvad-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Mullvad Browser Commits: c3546be5 by Beatriz Rizental at 2025-09-08T19:32:45+02:00 BB 43564: Modify ./mach bootstrap for Base Browser - - - - - 802cceaf by Beatriz Rizental at 2025-09-08T19:32:46+02:00 fixup! BB 43564: Modify ./mach bootstrap for Base Browser EXTRA: Stop asking to configure git during bootstrap. - - - - - 856dc4ee by Beatriz Rizental at 2025-09-08T19:32:47+02:00 fixup! BB 43564: Modify ./mach bootstrap for Base Browser - - - - - a1b3a8cf by Beatriz Rizental at 2025-09-08T19:32:47+02:00 fixup! BB 41803: Add some developer tools for working on tor-browser. - - - - - 4d66d017 by Beatriz Rizental at 2025-09-08T19:32:48+02:00 fixup! BB 43564: Modify ./mach bootstrap for Base Browser - - - - - 642024c9 by Beatriz Rizental at 2025-09-08T19:32:49+02:00 fixup! BB 43564: Modify ./mach bootstrap for Base Browser - - - - - 25 changed files: - + build/moz.configure/basebrowser-resources.configure - build/moz.configure/bootstrap.configure - build/moz.configure/init.configure - moz.configure - python/mozboot/mozboot/bootstrap.py - python/mozbuild/mozbuild/action/tooltool.py - python/mozbuild/mozbuild/artifact_commands.py - python/mozbuild/mozbuild/backend/base.py - + python/mozbuild/mozbuild/tbbutils.py - python/mozbuild/mozbuild/test/python.toml - + python/mozbuild/mozbuild/test/test_tbbutils.py - − tools/base-browser/l10n/combine/tests/README - tools/base-browser/git-rebase-fixup-preprocessor → tools/base_browser/git-rebase-fixup-preprocessor - tools/base-browser/l10n/combine-translation-versions.py → tools/base_browser/l10n/combine-translation-versions.py - tools/base-browser/l10n/combine/__init__.py → tools/base_browser/l10n/combine/__init__.py - tools/base-browser/l10n/combine/combine.py → tools/base_browser/l10n/combine/combine.py - tools/base-browser/l10n/combine/tests/__init__.py → tools/base_browser/l10n/combine/tests/__init__.py - + tools/base_browser/l10n/combine/tests/python.toml - tools/base-browser/l10n/combine/tests/test_android.py → tools/base_browser/l10n/combine/tests/test_android.py - tools/base-browser/l10n/combine/tests/test_dtd.py → tools/base_browser/l10n/combine/tests/test_dtd.py - tools/base-browser/l10n/combine/tests/test_fluent.py → tools/base_browser/l10n/combine/tests/test_fluent.py - tools/base-browser/l10n/combine/tests/test_properties.py → tools/base_browser/l10n/combine/tests/test_properties.py - tools/base-browser/missing-css-variables.py → tools/base_browser/missing-css-variables.py - tools/base-browser/tb-dev → tools/base_browser/tb-dev - tools/moz.build Changes: ===================================== build/moz.configure/basebrowser-resources.configure ===================================== @@ -0,0 +1,88 @@ +# Helpers +# ------------------------------------------------- + + +@depends(build_project) +def is_desktop_build(build_project): + return build_project == "browser" + + +# Bootstrap resources +# ------------------------------------------------- + + +option( + "--with-noscript", + env="NOSCRIPT", + nargs=1, + default=None, + help="Path to noscript .xpi extension archive.", +) + + +@depends( + "--with-noscript", + mozbuild_state_path, + bootstrap_path( + "noscript", no_unpack=True, when=depends("--with-noscript")(lambda x: not x) + ), +) +@checking("for noscript") +@imports(_from="pathlib", _import="Path") +def noscript(value, mozbuild_state_path, _bootstrapped): + if value: + path = Path(value[0]) + if path.is_file() and path.suffix == ".xpi": + return value[0] + else: + die("--with-noscript must be an existing .xpi file") + + bootstrapped_location = Path(mozbuild_state_path) / "browser" + for file in bootstrapped_location.glob(f"*.xpi"): + if "noscript" in file.name: + return str(bootstrapped_location / file) + + # noscript is not required for building. + return None + + +set_config("NOSCRIPT", noscript) + + +option( + "--with-tor-browser-fonts", + env="TOR_BROWSER_FONTS", + nargs=1, + default=None, + help="Path to location of fonts directory.", +) + + +@depends( + "--with-tor-browser-fonts", + mozbuild_state_path, + bootstrap_path( + "fonts", + when=depends("--with-tor-browser-fonts")(lambda x: not x) & is_desktop_build, + ), +) +@checking("for tor-browser fonts directory") +@imports(_from="pathlib", _import="Path") +def tor_browser_fonts(value, mozbuild_state_path, _bootstrapped): + if value: + path = Path(value[0]) + # TODO: Do a more thorough check on the directory. + if path.is_dir(): + return value[0] + else: + die("--with-tor-browser-fonts must point to a real directory.") + + bootstrapped_location = Path(mozbuild_state_path) / "fonts" + if bootstrapped_location.is_dir(): + return str(bootstrapped_location) + + # tor browser fonts directory is not required for building. + return None + + +set_config("TOR_BROWSER_FONTS", tor_browser_fonts) ===================================== build/moz.configure/bootstrap.configure ===================================== @@ -4,6 +4,29 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +option( + "--with-tor-browser-build-out", + env="TOR_BROWSER_BUILD_OUT", + nargs=1, + default="https://tb-build-06.torproject.org/~tb-builder/tor-browser-build/out", + help="URL pointing to a Tor Browser Build out folder, served over HTTP[S].", +) + + +@depends("--with-tor-browser-build-out") +def tor_browser_build_out(value): + if value: + return value[0] + + +option( + "--enable-tor-browser-build-only-bootstrap", + env="TBB_ONLY_BOOTSTRAP", + default=False, + help="Flag that disables bootstrapping any artifact from Mozilla's Taskcluster. Will only bootstrap artifacts from tor-browser-build.", +) + + option( env="MOZ_FETCHES_DIR", nargs=1, @@ -115,9 +138,10 @@ def bootstrap_toolchain_tasks(host): def bootstrap_path(path, **kwargs): when = kwargs.pop("when", None) allow_failure = kwargs.pop("allow_failure", None) + no_unpack = kwargs.pop("no_unpack", False) if kwargs: configure_error( - "bootstrap_path only takes `when` and `allow_failure` as a keyword argument" + "bootstrap_path only takes `when`, `allow_failure` and `no_unpack` as keyword arguments" ) @depends( @@ -129,11 +153,16 @@ def bootstrap_path(path, **kwargs): build_environment, dependable(path), dependable(allow_failure), + dependable(no_unpack), + tor_browser_build_out, + "--enable-tor-browser-build-only-bootstrap", + target, when=when, ) @imports("os") @imports("subprocess") @imports("sys") + @imports("mozbuild.tbbutils") @imports(_from="mozbuild.dirutils", _import="ensureParentDir") @imports(_from="importlib", _import="import_module") @imports(_from="shutil", _import="rmtree") @@ -148,6 +177,10 @@ def bootstrap_path(path, **kwargs): build_env, path, allow_failure, + no_unpack, + tor_browser_build_out, + tbb_only_bootstrap, + target, ): if not path: return @@ -158,6 +191,83 @@ def bootstrap_path(path, **kwargs): if path_parts[0] == "clang-tools": path_prefix = path_parts.pop(0) + # Small hack because noscript is inside the browser folder. + if path_parts[0] == "noscript": + path_prefix = "browser" + + def try_tbb_bootstrap(exists): + if not tor_browser_build_out: + return False + + # Tor browser build doesn't have artifacts for all targets supported + # by the Firefox build system. When this is empty it means we are + # building for a platform which tbb doesn't support. + if not target.tor_browser_build_alias: + return False + + artifact = mozbuild.tbbutils.get_artifact_name(path_parts[0], tasks.prefix) + if not artifact: + log.info("%s is not mapped to a tbb artifact", path_parts[0]) + return False + + artifact_path = mozbuild.tbbutils.get_artifact_path( + tor_browser_build_out, + artifact, + target, + prefix=path_prefix, + log=log.warning, + ) + if not artifact_path: + log.info("no path found in tbb/out for %s", artifact) + return False + + # We will use the name of the artifact as the index. + # + # It's usually unique to the artifact version, but each artifact follows + # a different naming convention, so we can't really get more specific here. + artifact_index = artifact_path.rsplit("/", 1)[-1] + index_file = os.path.join(toolchains_base_dir, "indices", artifact) + try: + with open(index_file) as fh: + index = fh.read().strip() + except Exception: + index = None + if index == artifact_index and exists: + log.debug("%s is up-to-date", artifact) + return True + + command = ["artifact", "toolchain", "--from-url", artifact_path] + + if no_unpack: + command.append("--no-unpack") + + # Note to rebasers: + # From here on, it's a slightly modified copy/paste + # from the end of the try_bootstrap function + log.info( + "%s bootstrapped toolchain from TBB in %s", + "Updating" if exists else "Installing", + os.path.join(toolchains_base_dir, path_prefix, artifact), + ) + os.makedirs(os.path.join(toolchains_base_dir, path_prefix), exist_ok=True) + proc = subprocess.run( + [ + sys.executable, + os.path.join(build_env.topsrcdir, "mach"), + "--log-no-times", + ] + + command, + cwd=os.path.join(toolchains_base_dir, path_prefix), + check=not allow_failure, + ) + if proc.returncode != 0 and allow_failure: + return False + ensureParentDir(index_file) + with open(index_file, "w") as fh: + fh.write(artifact_index) + + return True + def try_bootstrap(exists): if not tasks: return False @@ -280,9 +390,10 @@ def bootstrap_path(path, **kwargs): try: # With --enable-bootstrap=no-update, we don't `try_bootstrap`, except # when the toolchain can't be found. - if ( - "no-update" not in enable_bootstrap or not exists - ) and not try_bootstrap(exists): + if ("no-update" not in enable_bootstrap or not exists) and not ( + try_tbb_bootstrap(exists) + or (not tbb_only_bootstrap and try_bootstrap(exists)) + ): # If there aren't toolchain artifacts to use for this build, # don't return a path. return None ===================================== build/moz.configure/init.configure ===================================== @@ -590,6 +590,21 @@ def split_triplet(triplet, allow_wasi=False): else: toolchain = "%s-%s" % (cpu, os) + # In tor-browser-build we use slightly different terminology for + # the supported platforms. Let's prepare that OS string here. + # + # Not all possible platforms listed here are supported in tbb, + # so this value will be empty sometimes. + tor_browser_build_alias = None + if canonical_os == "Android" and canonical_kernel == "Linux": + tor_browser_build_alias = f"android" + elif canonical_os == "GNU" and canonical_kernel == "Linux": + tor_browser_build_alias = f"linux" + elif canonical_os == "OSX" and canonical_kernel == "Darwin": + tor_browser_build_alias = f"macos" + elif canonical_os == "WINNT" and canonical_kernel == "WINNT": + tor_browser_build_alias = f"windows" + return namespace( alias=triplet, cpu=CPU(canonical_cpu), @@ -604,6 +619,7 @@ def split_triplet(triplet, allow_wasi=False): toolchain=toolchain, vendor=vendor, sub_configure_alias=sub_configure_alias, + tor_browser_build_alias=tor_browser_build_alias, ) ===================================== moz.configure ===================================== @@ -229,6 +229,7 @@ check_prog("WGET", ("wget",), allow_missing=True) include("build/moz.configure/toolchain.configure", when="--enable-compile-environment") +include("build/moz.configure/basebrowser-resources.configure") include("build/moz.configure/pkg.configure") include("build/moz.configure/memory.configure", when="--enable-compile-environment") ===================================== python/mozboot/mozboot/bootstrap.py ===================================== @@ -52,21 +52,28 @@ Note on Artifact Mode: Artifact builds download prebuilt C++ components rather than building them locally. Artifact builds are faster! -Artifact builds are recommended for people working on Firefox or -Firefox for Android frontends, or the GeckoView Java API. They are unsuitable +Artifact builds are recommended for people working on Tor Browser or +Base Browser for Android frontends, or the GeckoView Java API. They are unsuitable for those working on C++ code. For more information see: https://firefox-source-docs.mozilla.org/contributing/build/artifact_builds.…. -Please choose the version of Firefox you want to build (see note above): +# Note to Base Browser developers + +This is still highly experimental. Expect bugs! + +Please choose the version of Base Browser you want to build (see note above): %s Your choice: """ APPLICATIONS = OrderedDict( [ - ("Firefox for Desktop Artifact Mode", "browser_artifact_mode"), - ("Firefox for Desktop", "browser"), - ("GeckoView/Firefox for Android Artifact Mode", "mobile_android_artifact_mode"), - ("GeckoView/Firefox for Android", "mobile_android"), + ("Base Browser for Desktop Artifact Mode", "browser_artifact_mode"), + ("Base Browser for Desktop", "browser"), + ( + "GeckoView/Base Browser for Android Artifact Mode", + "mobile_android_artifact_mode", + ), + ("GeckoView/Base Browser for Android", "mobile_android"), ("SpiderMonkey JavaScript engine", "js"), ] ) @@ -360,6 +367,8 @@ class Bootstrapper: getattr(self.instance, "ensure_%s_packages" % application)() def check_code_submission(self, checkout_root: Path): + return + if self.instance.no_interactive or which("moz-phab"): return @@ -474,8 +483,7 @@ class Bootstrapper: configure_mercurial(hg, state_dir) # Offer to configure Git, if the current checkout or repo type is Git. - elif git and checkout_type == "git": - should_configure_git = False + elif False and git and checkout_type == "git": if not self.instance.no_interactive: should_configure_git = self.instance.prompt_yesno(prompt=CONFIGURE_GIT) else: ===================================== python/mozbuild/mozbuild/action/tooltool.py ===================================== @@ -1029,14 +1029,29 @@ def unpack_file(filename): """Untar `filename`, assuming it is uncompressed or compressed with bzip2, xz, gzip, zst, or unzip a zip file. The file is assumed to contain a single directory with a name matching the base of the given filename. - Xz support is handled by shelling out to 'tar'.""" + Xz support is handled by shelling out to 'tar'. + + tor-browser#41564 - For supporting tor-browser-build artifacts that contain + multiple directories, the archive is extracted into a directory with the + same name as the base of the filename. This modification is only applied to + tar archives, because that is all that was necessary. + """ if os.path.isfile(filename) and tarfile.is_tarfile(filename): tar_file, zip_ext = os.path.splitext(filename) base_file, tar_ext = os.path.splitext(tar_file) clean_path(base_file) log.info('untarring "%s"' % filename) with TarFile.open(filename) as tar: - safe_extract(tar) + top_level_directories = set() + for name in tar.getnames(): + dir = name.split("/", 1)[0] + top_level_directories.add(dir) + if len(top_level_directories) == 1: + safe_extract(tar) + else: + safe_extract( + tar, path=os.path.join(os.path.dirname(filename), base_file) + ) elif os.path.isfile(filename) and filename.endswith(".tar.zst"): import zstandard ===================================== python/mozbuild/mozbuild/artifact_commands.py ===================================== @@ -244,6 +244,12 @@ def artifact_clear_cache(command_context, tree=None, job=None, verbose=False): nargs="+", help="Download toolchain artifact from a given task.", ) +@CommandArgument( + "--from-url", + metavar="URL", + nargs="+", + help="Download toolchain artifact from an arbitrary address.", +) @CommandArgument( "--tooltool-manifest", metavar="MANIFEST", @@ -273,6 +279,7 @@ def artifact_toolchain( skip_cache=False, from_build=(), from_task=(), + from_url=[], tooltool_manifest=None, no_unpack=False, retry=0, @@ -504,6 +511,13 @@ def artifact_toolchain( record = ArtifactRecord(task_id, name) records[record.filename] = record + if from_url: + for file in from_url: + record = DownloadRecord( + file, file.rsplit("/", 1)[-1], None, None, None, True + ) + records[record.filename] = record + for record in records.values(): command_context.log( logging.INFO, ===================================== python/mozbuild/mozbuild/backend/base.py ===================================== @@ -2,11 +2,14 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +import errno import itertools +import logging import os import time from abc import ABCMeta, abstractmethod from contextlib import contextmanager +from pathlib import Path import mozpack.path as mozpath from mach.mixin.logging import LoggingMixin @@ -239,6 +242,72 @@ class BuildBackend(LoggingMixin): with open(mozpath.join(dir, ".purgecaches"), "w") as f: f.write("\n") + def _setup_tor_browser_environment(self, config): + app = config.substs["MOZ_BUILD_APP"] + + noscript_target_filename = "{73a6fe31-595d-460b-a920-fcc0f8843232}.xpi" + noscript_location = config.substs.get("NOSCRIPT") + + def _infallible_symlink(src, dst): + try: + os.symlink(src, dst) + except OSError as e: + if e.errno == errno.EEXIST: + # If the symlink already exists, remove it and try again. + os.remove(dst) + os.symlink(src, dst) + else: + return + + if app == "browser": + tbdir = Path(config.topobjdir) / "dist" / "bin" + + if config.substs.get("OS_TARGET") == "Darwin": + tbdir = next(tbdir.glob("*.app")) + paths = { + "docs": tbdir / "Contents/Resources/TorBrowser/Docs", + "exts": tbdir / "Contents/Resources/distribution/extensions", + "fonts": tbdir / "Resources/fonts", + } + else: + paths = { + "docs": tbdir / "TorBrowser/Docs", + "exts": tbdir / "distribution/extensions", + "fonts": tbdir / "fonts", + } + + fonts_location = config.substs.get("TOR_BROWSER_FONTS") + if fonts_location: + self.log( + logging.INFO, + "_setup_tor_browser_environment", + { + "fonts_location": fonts_location, + "fonts_target": str(paths["fonts"]), + }, + "Creating symlink for fonts files from {fonts_location} to {fonts_target}", + ) + + for file in Path(fonts_location).iterdir(): + target = paths["fonts"] / file.name + _infallible_symlink(file, target) + + # Set up NoScript extension + if noscript_location: + noscript_target = paths["exts"] / noscript_target_filename + self.log( + logging.INFO, + "_setup_tor_browser_environment", + { + "noscript_location": noscript_location, + "noscript_target": str(noscript_target), + }, + "Creating symlink for NoScript from {noscript_location} to {noscript_target}", + ) + + paths["exts"].mkdir(parents=True, exist_ok=True) + _infallible_symlink(noscript_location, noscript_target) + def post_build(self, config, output, jobs, verbose, status): """Called late during 'mach build' execution, after `build(...)` has finished. @@ -257,6 +326,9 @@ class BuildBackend(LoggingMixin): """ self._write_purgecaches(config) + if status == 0: + self._setup_tor_browser_environment(config) + return status @contextmanager ===================================== python/mozbuild/mozbuild/tbbutils.py ===================================== @@ -0,0 +1,103 @@ +import re +from urllib.request import Request, urlopen + + +def list_files_http(url): + try: + req = Request(url, method="GET") + with urlopen(req) as response: + if response.status != 200: + return [] + html = response.read().decode() + except Exception: + return [] + + links = [] + for href in re.findall(r'<a href="([^"]+)"', html): + if href == "../": + continue + + links.append(href) + + return links + + +TOR_BROWSER_BUILD_ARTIFACTS = [ + # Tor Browser Build-only artifacts, these artifacts are not common with Firefox. + "noscript", + "fonts", +] + +# Mapping of artifacts from taskcluster to tor-browser-build. +ARTIFACT_NAME_MAP = { + "cbindgen": "cbindgen", + # FIXME (tor-browser-build#41471): nasm is more or less ready to go, but it needs to have the + # executable in the root of the artifact folder instead of nasm/bin. + # "nasm": "nasm", + # FIXME (tor-browser-build#41421): the clang project as is, is not ready to use. It needs + # to be repackaged with a bunch of things that differ per platform. Fun stuff. + # "clang": "clang", + "node": "node", +} + + +def get_artifact_name(original_artifact_name, host): + # These are not build artifacts, they are pre-built artifacts to be added to the final build, + # therefore this check can come before the host check. + if original_artifact_name in TOR_BROWSER_BUILD_ARTIFACTS: + return original_artifact_name + + if host != "linux64": + # Tor browser build only has development artifacts for linux64 host systems. + return None + + return ARTIFACT_NAME_MAP.get(original_artifact_name) + + +def get_artifact_path(url, artifact, target, prefix="", log=lambda *args, **kwargs: {}): + if prefix: + path = prefix + else: + path = artifact + + # The `?C=M;O=D` parameters make it so links are ordered by + # the last modified date. This here to make us get the latest + # version of file in the case there are multiple and we just + # grab the first one. + files = list_files_http(f"{url}/{path}?C=M;O=D") + + if not files: + log(f"No files found in {url} for {artifact}.") + return None + + def filter_files(files, keyword): + return [file for file in files if keyword in file] + + artifact_files = [file for file in files if file.startswith(artifact)] + + if len(artifact_files) == 0: + log(f"No files found in {url} for {artifact}.") + return None + + if len(artifact_files) == 1: + return f"{url}/{path}/{artifact_files[0]}" + + files_per_os = filter_files(artifact_files, target.tor_browser_build_alias) + + # If there are files in the folder, but they don't have the OS in the name + # it probably means we can get any of them because they can be used to build + # for any OS. So let's just get the first one. + # + # Note: It could be the case that the artifact _is_ OS dependant, but there + # just are no files for the OS we are looking for. In that case, this will + # return an incorrect artifact. This should not happen often though and is + # something we cannot address until artifact names are standardized on tbb. + if len(files_per_os) == 0: + return f"{url}/{artifact}/{artifact_files[0]}" + + elif len(files_per_os) == 1: + return f"{url}/{artifact}/{files_per_os[0]}" + + matches = filter_files(files_per_os, target.cpu) + + return f"{url}/{artifact}/{matches[0]}" if matches else None ===================================== python/mozbuild/mozbuild/test/python.toml ===================================== @@ -111,6 +111,9 @@ subsuite = "mozbuild" ["test_rewrite_mozbuild.py"] +["test_tbbutils.py"] +subsuite = "base-browser" + ["test_telemetry.py"] ["test_telemetry_settings.py"] ===================================== python/mozbuild/mozbuild/test/test_tbbutils.py ===================================== @@ -0,0 +1,139 @@ +import unittest +from types import SimpleNamespace +from unittest.mock import MagicMock, patch + +import mozunit + +from mozbuild.tbbutils import get_artifact_path, list_files_http + + +class TestGetArtifactName(unittest.TestCase): + def setUp(self): + self.artifact = "artifact" + self.host = "linux64" + + @patch("mozbuild.tbbutils.TOR_BROWSER_BUILD_ARTIFACTS", new=["artifact"]) + def test_artifact_in_tbb_artifacts(self): + from mozbuild.tbbutils import get_artifact_name + + result = get_artifact_name(self.artifact, self.host) + self.assertEqual(result, self.artifact) + + @patch("mozbuild.tbbutils.ARTIFACT_NAME_MAP", new={"artifact": "tcafitra"}) + def test_host_is_not_linux64(self): + from mozbuild.tbbutils import get_artifact_name + + result = get_artifact_name(self.artifact, "linux64-aarch64") + self.assertIsNone(result) + + @patch("mozbuild.tbbutils.ARTIFACT_NAME_MAP", new={"artifact": "tcafitra"}) + def test_mapped_artifact(self): + from mozbuild.tbbutils import get_artifact_name + + result = get_artifact_name(self.artifact, self.host) + self.assertEqual(result, self.artifact[::-1]) + + +class TestGetArtifactPath(unittest.TestCase): + def setUp(self): + self.url = "http://example.com" + self.artifact = "artifact" + # This is just an example target which is valid. But it doesn't make + # any difference and could be anything for these tests. + self.target = SimpleNamespace(tor_browser_build_alias="linux", cpu="x86_64") + + @patch("mozbuild.tbbutils.list_files_http") + def test_no_files_returns_none(self, mock_list_files): + mock_list_files.return_value = [] + result = get_artifact_path(self.url, self.artifact, self.target) + self.assertIsNone(result) + + @patch("mozbuild.tbbutils.list_files_http") + def test_no_matching_files_returns_none(self, mock_list_files): + mock_list_files.return_value = ["somethingelse.zip", "yetanotherthing.zip"] + result = get_artifact_path(self.url, self.artifact, self.target) + self.assertIsNone(result) + + @patch("mozbuild.tbbutils.list_files_http") + def test_single_artifact_match(self, mock_list_files): + mock_list_files.return_value = ["artifact-1.zip"] + result = get_artifact_path(self.url, self.artifact, self.target) + self.assertEqual(result, f"{self.url}/{self.artifact}/artifact-1.zip") + + @patch("mozbuild.tbbutils.list_files_http") + def test_artifact_without_os_returns_first(self, mock_list_files): + mock_list_files.return_value = ["artifact-1.zip", "artifact-2.zip"] + result = get_artifact_path(self.url, self.artifact, self.target) + self.assertTrue(result.startswith(f"{self.url}/{self.artifact}/")) + self.assertIn("artifact-", result) + + @patch("mozbuild.tbbutils.list_files_http") + def test_artifact_with_os_match(self, mock_list_files): + mock_list_files.return_value = [ + "artifact-windows.zip", + "artifact-linux.zip", + ] + result = get_artifact_path(self.url, self.artifact, self.target) + self.assertEqual(result, f"{self.url}/{self.artifact}/artifact-linux.zip") + + @patch("mozbuild.tbbutils.list_files_http") + def test_artifact_with_cpu_match(self, mock_list_files): + mock_list_files.return_value = [ + "artifact-linux-arm.zip", + "artifact-linux-x86_64.zip", + ] + result = get_artifact_path(self.url, self.artifact, self.target) + self.assertEqual( + result, f"{self.url}/{self.artifact}/artifact-linux-x86_64.zip" + ) + + @patch("mozbuild.tbbutils.list_files_http") + def test_artifact_with_prefix(self, mock_list_files): + mock_list_files.return_value = ["artifact-1.zip"] + + prefix = "prefix" + result = get_artifact_path(self.url, self.artifact, self.target, prefix=prefix) + self.assertEqual(result, f"{self.url}/{prefix}/artifact-1.zip") + mock_list_files.assert_called_with(f"{self.url}/{prefix}?C=M;O=D") + + +class TestListFilesHttp(unittest.TestCase): + def setUp(self): + self.url = "http://example.com" + + @patch("mozbuild.tbbutils.urlopen") + def test_non_200_status_returns_empty(self, mock_urlopen): + mock_resp = MagicMock() + mock_resp.status = 404 + mock_resp.read.return_value = b"" + mock_urlopen.return_value.__enter__.return_value = mock_resp + + result = list_files_http(self.url) + self.assertEqual(result, []) + + @patch("mozbuild.tbbutils.urlopen") + def test_exception_returns_empty(self, mock_urlopen): + mock_urlopen.side_effect = Exception("network error") + result = list_files_http(self.url) + self.assertEqual(result, []) + + @patch("mozbuild.tbbutils.urlopen") + def test_regular_links(self, mock_urlopen): + html = b""" + <html><body> + <a href="../">Parent</a> + <a href="file1.zip">file1</a> + <a href="file2.zip">file2</a> + </body></html> + """ + mock_resp = MagicMock() + mock_resp.status = 200 + mock_resp.read.return_value = html + mock_urlopen.return_value.__enter__.return_value = mock_resp + + result = list_files_http(self.url) + self.assertEqual(result, ["file1.zip", "file2.zip"]) + + +if __name__ == "__main__": + mozunit.main() ===================================== tools/base-browser/l10n/combine/tests/README deleted ===================================== @@ -1,2 +0,0 @@ -python tests to be run with pytest. -Requires the compare-locales package. ===================================== tools/base-browser/git-rebase-fixup-preprocessor → tools/base_browser/git-rebase-fixup-preprocessor ===================================== ===================================== tools/base-browser/l10n/combine-translation-versions.py → tools/base_browser/l10n/combine-translation-versions.py ===================================== ===================================== tools/base-browser/l10n/combine/__init__.py → tools/base_browser/l10n/combine/__init__.py ===================================== ===================================== tools/base-browser/l10n/combine/combine.py → tools/base_browser/l10n/combine/combine.py ===================================== ===================================== tools/base-browser/l10n/combine/tests/__init__.py → tools/base_browser/l10n/combine/tests/__init__.py ===================================== ===================================== tools/base_browser/l10n/combine/tests/python.toml ===================================== @@ -0,0 +1,10 @@ +[DEFAULT] +subsuite = "base-browser" + +["test_android.py"] + +["test_dtd.py"] + +["test_fluent.py"] + +["test_properties.py"] ===================================== tools/base-browser/l10n/combine/tests/test_android.py → tools/base_browser/l10n/combine/tests/test_android.py ===================================== @@ -1,6 +1,7 @@ import textwrap -from combine import combine_files +import mozunit +from base_browser.l10n.combine import combine_files def wrap_in_xml(content): @@ -413,3 +414,7 @@ def test_alternatives(): <string name="string_4_alt">Other string</string> """, ) + + +if __name__ == "__main__": + mozunit.main() ===================================== tools/base-browser/l10n/combine/tests/test_dtd.py → tools/base_browser/l10n/combine/tests/test_dtd.py ===================================== @@ -1,6 +1,7 @@ import textwrap -from combine import combine_files +import mozunit +from base_browser.l10n.combine import combine_files def assert_result(new_content, old_content, expect): @@ -411,3 +412,7 @@ def test_alternatives(): <!ENTITY string.4.alt "Other string"> """, ) + + +if __name__ == "__main__": + mozunit.main() ===================================== tools/base-browser/l10n/combine/tests/test_fluent.py → tools/base_browser/l10n/combine/tests/test_fluent.py ===================================== @@ -1,6 +1,7 @@ import textwrap -from combine import combine_files +import mozunit +from base_browser.l10n.combine import combine_files def assert_result(new_content, old_content, expect): @@ -475,3 +476,7 @@ def test_alternatives(): -string-4-alt = Other string """, ) + + +if __name__ == "__main__": + mozunit.main() ===================================== tools/base-browser/l10n/combine/tests/test_properties.py → tools/base_browser/l10n/combine/tests/test_properties.py ===================================== @@ -1,6 +1,7 @@ import textwrap -from combine import combine_files +import mozunit +from base_browser.l10n.combine import combine_files def assert_result(new_content, old_content, expect): @@ -408,3 +409,7 @@ def test_alternatives(): string.4.alt = Other string """, ) + + +if __name__ == "__main__": + mozunit.main() ===================================== tools/base-browser/missing-css-variables.py → tools/base_browser/missing-css-variables.py ===================================== ===================================== tools/base-browser/tb-dev → tools/base_browser/tb-dev ===================================== ===================================== tools/moz.build ===================================== @@ -71,6 +71,7 @@ with Files("tryselect/docs/**"): SCHEDULES.exclusive = ["docs"] PYTHON_UNITTEST_MANIFESTS += [ + "base_browser/l10n/combine/tests/python.toml", "fuzzing/smoke/python.toml", "lint/test/python.toml", "tryselect/test/python.toml", View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/a5… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/a5… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][base-browser-140.2.0esr-15.0-1] 6 commits: BB 43564: Modify ./mach bootstrap for Base Browser
by brizental (@brizental) 08 Sep '25

08 Sep '25
brizental pushed to branch base-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser Commits: 85b4d8d5 by Beatriz Rizental at 2025-09-08T19:22:50+02:00 BB 43564: Modify ./mach bootstrap for Base Browser - - - - - 02a18b4d by Beatriz Rizental at 2025-09-08T19:22:58+02:00 fixup! BB 43564: Modify ./mach bootstrap for Base Browser EXTRA: Stop asking to configure git during bootstrap. - - - - - 4937c1b6 by Beatriz Rizental at 2025-09-08T19:23:06+02:00 fixup! BB 43564: Modify ./mach bootstrap for Base Browser - - - - - 98a01dbd by Beatriz Rizental at 2025-09-08T19:23:32+02:00 fixup! BB 41803: Add some developer tools for working on tor-browser. - - - - - 10ce4ee0 by Beatriz Rizental at 2025-09-08T19:28:44+02:00 fixup! BB 43564: Modify ./mach bootstrap for Base Browser - - - - - e841a083 by Beatriz Rizental at 2025-09-08T19:28:49+02:00 fixup! BB 43564: Modify ./mach bootstrap for Base Browser - - - - - 25 changed files: - + build/moz.configure/basebrowser-resources.configure - build/moz.configure/bootstrap.configure - build/moz.configure/init.configure - moz.configure - python/mozboot/mozboot/bootstrap.py - python/mozbuild/mozbuild/action/tooltool.py - python/mozbuild/mozbuild/artifact_commands.py - python/mozbuild/mozbuild/backend/base.py - + python/mozbuild/mozbuild/tbbutils.py - python/mozbuild/mozbuild/test/python.toml - + python/mozbuild/mozbuild/test/test_tbbutils.py - − tools/base-browser/l10n/combine/tests/README - tools/base-browser/git-rebase-fixup-preprocessor → tools/base_browser/git-rebase-fixup-preprocessor - tools/base-browser/l10n/combine-translation-versions.py → tools/base_browser/l10n/combine-translation-versions.py - tools/base-browser/l10n/combine/__init__.py → tools/base_browser/l10n/combine/__init__.py - tools/base-browser/l10n/combine/combine.py → tools/base_browser/l10n/combine/combine.py - tools/base-browser/l10n/combine/tests/__init__.py → tools/base_browser/l10n/combine/tests/__init__.py - + tools/base_browser/l10n/combine/tests/python.toml - tools/base-browser/l10n/combine/tests/test_android.py → tools/base_browser/l10n/combine/tests/test_android.py - tools/base-browser/l10n/combine/tests/test_dtd.py → tools/base_browser/l10n/combine/tests/test_dtd.py - tools/base-browser/l10n/combine/tests/test_fluent.py → tools/base_browser/l10n/combine/tests/test_fluent.py - tools/base-browser/l10n/combine/tests/test_properties.py → tools/base_browser/l10n/combine/tests/test_properties.py - tools/base-browser/missing-css-variables.py → tools/base_browser/missing-css-variables.py - tools/base-browser/tb-dev → tools/base_browser/tb-dev - tools/moz.build Changes: ===================================== build/moz.configure/basebrowser-resources.configure ===================================== @@ -0,0 +1,88 @@ +# Helpers +# ------------------------------------------------- + + +@depends(build_project) +def is_desktop_build(build_project): + return build_project == "browser" + + +# Bootstrap resources +# ------------------------------------------------- + + +option( + "--with-noscript", + env="NOSCRIPT", + nargs=1, + default=None, + help="Path to noscript .xpi extension archive.", +) + + +@depends( + "--with-noscript", + mozbuild_state_path, + bootstrap_path( + "noscript", no_unpack=True, when=depends("--with-noscript")(lambda x: not x) + ), +) +@checking("for noscript") +@imports(_from="pathlib", _import="Path") +def noscript(value, mozbuild_state_path, _bootstrapped): + if value: + path = Path(value[0]) + if path.is_file() and path.suffix == ".xpi": + return value[0] + else: + die("--with-noscript must be an existing .xpi file") + + bootstrapped_location = Path(mozbuild_state_path) / "browser" + for file in bootstrapped_location.glob(f"*.xpi"): + if "noscript" in file.name: + return str(bootstrapped_location / file) + + # noscript is not required for building. + return None + + +set_config("NOSCRIPT", noscript) + + +option( + "--with-tor-browser-fonts", + env="TOR_BROWSER_FONTS", + nargs=1, + default=None, + help="Path to location of fonts directory.", +) + + +@depends( + "--with-tor-browser-fonts", + mozbuild_state_path, + bootstrap_path( + "fonts", + when=depends("--with-tor-browser-fonts")(lambda x: not x) & is_desktop_build, + ), +) +@checking("for tor-browser fonts directory") +@imports(_from="pathlib", _import="Path") +def tor_browser_fonts(value, mozbuild_state_path, _bootstrapped): + if value: + path = Path(value[0]) + # TODO: Do a more thorough check on the directory. + if path.is_dir(): + return value[0] + else: + die("--with-tor-browser-fonts must point to a real directory.") + + bootstrapped_location = Path(mozbuild_state_path) / "fonts" + if bootstrapped_location.is_dir(): + return str(bootstrapped_location) + + # tor browser fonts directory is not required for building. + return None + + +set_config("TOR_BROWSER_FONTS", tor_browser_fonts) ===================================== build/moz.configure/bootstrap.configure ===================================== @@ -4,6 +4,29 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +option( + "--with-tor-browser-build-out", + env="TOR_BROWSER_BUILD_OUT", + nargs=1, + default="https://tb-build-06.torproject.org/~tb-builder/tor-browser-build/out", + help="URL pointing to a Tor Browser Build out folder, served over HTTP[S].", +) + + +@depends("--with-tor-browser-build-out") +def tor_browser_build_out(value): + if value: + return value[0] + + +option( + "--enable-tor-browser-build-only-bootstrap", + env="TBB_ONLY_BOOTSTRAP", + default=False, + help="Flag that disables bootstrapping any artifact from Mozilla's Taskcluster. Will only bootstrap artifacts from tor-browser-build.", +) + + option( env="MOZ_FETCHES_DIR", nargs=1, @@ -115,9 +138,10 @@ def bootstrap_toolchain_tasks(host): def bootstrap_path(path, **kwargs): when = kwargs.pop("when", None) allow_failure = kwargs.pop("allow_failure", None) + no_unpack = kwargs.pop("no_unpack", False) if kwargs: configure_error( - "bootstrap_path only takes `when` and `allow_failure` as a keyword argument" + "bootstrap_path only takes `when`, `allow_failure` and `no_unpack` as keyword arguments" ) @depends( @@ -129,11 +153,16 @@ def bootstrap_path(path, **kwargs): build_environment, dependable(path), dependable(allow_failure), + dependable(no_unpack), + tor_browser_build_out, + "--enable-tor-browser-build-only-bootstrap", + target, when=when, ) @imports("os") @imports("subprocess") @imports("sys") + @imports("mozbuild.tbbutils") @imports(_from="mozbuild.dirutils", _import="ensureParentDir") @imports(_from="importlib", _import="import_module") @imports(_from="shutil", _import="rmtree") @@ -148,6 +177,10 @@ def bootstrap_path(path, **kwargs): build_env, path, allow_failure, + no_unpack, + tor_browser_build_out, + tbb_only_bootstrap, + target, ): if not path: return @@ -158,6 +191,83 @@ def bootstrap_path(path, **kwargs): if path_parts[0] == "clang-tools": path_prefix = path_parts.pop(0) + # Small hack because noscript is inside the browser folder. + if path_parts[0] == "noscript": + path_prefix = "browser" + + def try_tbb_bootstrap(exists): + if not tor_browser_build_out: + return False + + # Tor browser build doesn't have artifacts for all targets supported + # by the Firefox build system. When this is empty it means we are + # building for a platform which tbb doesn't support. + if not target.tor_browser_build_alias: + return False + + artifact = mozbuild.tbbutils.get_artifact_name(path_parts[0], tasks.prefix) + if not artifact: + log.info("%s is not mapped to a tbb artifact", path_parts[0]) + return False + + artifact_path = mozbuild.tbbutils.get_artifact_path( + tor_browser_build_out, + artifact, + target, + prefix=path_prefix, + log=log.warning, + ) + if not artifact_path: + log.info("no path found in tbb/out for %s", artifact) + return False + + # We will use the name of the artifact as the index. + # + # It's usually unique to the artifact version, but each artifact follows + # a different naming convention, so we can't really get more specific here. + artifact_index = artifact_path.rsplit("/", 1)[-1] + index_file = os.path.join(toolchains_base_dir, "indices", artifact) + try: + with open(index_file) as fh: + index = fh.read().strip() + except Exception: + index = None + if index == artifact_index and exists: + log.debug("%s is up-to-date", artifact) + return True + + command = ["artifact", "toolchain", "--from-url", artifact_path] + + if no_unpack: + command.append("--no-unpack") + + # Note to rebasers: + # From here on, it's a slightly modified copy/paste + # from the end of the try_bootstrap function + log.info( + "%s bootstrapped toolchain from TBB in %s", + "Updating" if exists else "Installing", + os.path.join(toolchains_base_dir, path_prefix, artifact), + ) + os.makedirs(os.path.join(toolchains_base_dir, path_prefix), exist_ok=True) + proc = subprocess.run( + [ + sys.executable, + os.path.join(build_env.topsrcdir, "mach"), + "--log-no-times", + ] + + command, + cwd=os.path.join(toolchains_base_dir, path_prefix), + check=not allow_failure, + ) + if proc.returncode != 0 and allow_failure: + return False + ensureParentDir(index_file) + with open(index_file, "w") as fh: + fh.write(artifact_index) + + return True + def try_bootstrap(exists): if not tasks: return False @@ -280,9 +390,10 @@ def bootstrap_path(path, **kwargs): try: # With --enable-bootstrap=no-update, we don't `try_bootstrap`, except # when the toolchain can't be found. - if ( - "no-update" not in enable_bootstrap or not exists - ) and not try_bootstrap(exists): + if ("no-update" not in enable_bootstrap or not exists) and not ( + try_tbb_bootstrap(exists) + or (not tbb_only_bootstrap and try_bootstrap(exists)) + ): # If there aren't toolchain artifacts to use for this build, # don't return a path. return None ===================================== build/moz.configure/init.configure ===================================== @@ -590,6 +590,21 @@ def split_triplet(triplet, allow_wasi=False): else: toolchain = "%s-%s" % (cpu, os) + # In tor-browser-build we use slightly different terminology for + # the supported platforms. Let's prepare that OS string here. + # + # Not all possible platforms listed here are supported in tbb, + # so this value will be empty sometimes. + tor_browser_build_alias = None + if canonical_os == "Android" and canonical_kernel == "Linux": + tor_browser_build_alias = f"android" + elif canonical_os == "GNU" and canonical_kernel == "Linux": + tor_browser_build_alias = f"linux" + elif canonical_os == "OSX" and canonical_kernel == "Darwin": + tor_browser_build_alias = f"macos" + elif canonical_os == "WINNT" and canonical_kernel == "WINNT": + tor_browser_build_alias = f"windows" + return namespace( alias=triplet, cpu=CPU(canonical_cpu), @@ -604,6 +619,7 @@ def split_triplet(triplet, allow_wasi=False): toolchain=toolchain, vendor=vendor, sub_configure_alias=sub_configure_alias, + tor_browser_build_alias=tor_browser_build_alias, ) ===================================== moz.configure ===================================== @@ -229,6 +229,7 @@ check_prog("WGET", ("wget",), allow_missing=True) include("build/moz.configure/toolchain.configure", when="--enable-compile-environment") +include("build/moz.configure/basebrowser-resources.configure") include("build/moz.configure/pkg.configure") include("build/moz.configure/memory.configure", when="--enable-compile-environment") ===================================== python/mozboot/mozboot/bootstrap.py ===================================== @@ -52,21 +52,28 @@ Note on Artifact Mode: Artifact builds download prebuilt C++ components rather than building them locally. Artifact builds are faster! -Artifact builds are recommended for people working on Firefox or -Firefox for Android frontends, or the GeckoView Java API. They are unsuitable +Artifact builds are recommended for people working on Tor Browser or +Base Browser for Android frontends, or the GeckoView Java API. They are unsuitable for those working on C++ code. For more information see: https://firefox-source-docs.mozilla.org/contributing/build/artifact_builds.…. -Please choose the version of Firefox you want to build (see note above): +# Note to Base Browser developers + +This is still highly experimental. Expect bugs! + +Please choose the version of Base Browser you want to build (see note above): %s Your choice: """ APPLICATIONS = OrderedDict( [ - ("Firefox for Desktop Artifact Mode", "browser_artifact_mode"), - ("Firefox for Desktop", "browser"), - ("GeckoView/Firefox for Android Artifact Mode", "mobile_android_artifact_mode"), - ("GeckoView/Firefox for Android", "mobile_android"), + ("Base Browser for Desktop Artifact Mode", "browser_artifact_mode"), + ("Base Browser for Desktop", "browser"), + ( + "GeckoView/Base Browser for Android Artifact Mode", + "mobile_android_artifact_mode", + ), + ("GeckoView/Base Browser for Android", "mobile_android"), ("SpiderMonkey JavaScript engine", "js"), ] ) @@ -360,6 +367,8 @@ class Bootstrapper: getattr(self.instance, "ensure_%s_packages" % application)() def check_code_submission(self, checkout_root: Path): + return + if self.instance.no_interactive or which("moz-phab"): return @@ -474,8 +483,7 @@ class Bootstrapper: configure_mercurial(hg, state_dir) # Offer to configure Git, if the current checkout or repo type is Git. - elif git and checkout_type == "git": - should_configure_git = False + elif False and git and checkout_type == "git": if not self.instance.no_interactive: should_configure_git = self.instance.prompt_yesno(prompt=CONFIGURE_GIT) else: ===================================== python/mozbuild/mozbuild/action/tooltool.py ===================================== @@ -1029,14 +1029,29 @@ def unpack_file(filename): """Untar `filename`, assuming it is uncompressed or compressed with bzip2, xz, gzip, zst, or unzip a zip file. The file is assumed to contain a single directory with a name matching the base of the given filename. - Xz support is handled by shelling out to 'tar'.""" + Xz support is handled by shelling out to 'tar'. + + tor-browser#41564 - For supporting tor-browser-build artifacts that contain + multiple directories, the archive is extracted into a directory with the + same name as the base of the filename. This modification is only applied to + tar archives, because that is all that was necessary. + """ if os.path.isfile(filename) and tarfile.is_tarfile(filename): tar_file, zip_ext = os.path.splitext(filename) base_file, tar_ext = os.path.splitext(tar_file) clean_path(base_file) log.info('untarring "%s"' % filename) with TarFile.open(filename) as tar: - safe_extract(tar) + top_level_directories = set() + for name in tar.getnames(): + dir = name.split("/", 1)[0] + top_level_directories.add(dir) + if len(top_level_directories) == 1: + safe_extract(tar) + else: + safe_extract( + tar, path=os.path.join(os.path.dirname(filename), base_file) + ) elif os.path.isfile(filename) and filename.endswith(".tar.zst"): import zstandard ===================================== python/mozbuild/mozbuild/artifact_commands.py ===================================== @@ -244,6 +244,12 @@ def artifact_clear_cache(command_context, tree=None, job=None, verbose=False): nargs="+", help="Download toolchain artifact from a given task.", ) +@CommandArgument( + "--from-url", + metavar="URL", + nargs="+", + help="Download toolchain artifact from an arbitrary address.", +) @CommandArgument( "--tooltool-manifest", metavar="MANIFEST", @@ -273,6 +279,7 @@ def artifact_toolchain( skip_cache=False, from_build=(), from_task=(), + from_url=[], tooltool_manifest=None, no_unpack=False, retry=0, @@ -504,6 +511,13 @@ def artifact_toolchain( record = ArtifactRecord(task_id, name) records[record.filename] = record + if from_url: + for file in from_url: + record = DownloadRecord( + file, file.rsplit("/", 1)[-1], None, None, None, True + ) + records[record.filename] = record + for record in records.values(): command_context.log( logging.INFO, ===================================== python/mozbuild/mozbuild/backend/base.py ===================================== @@ -2,11 +2,14 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +import errno import itertools +import logging import os import time from abc import ABCMeta, abstractmethod from contextlib import contextmanager +from pathlib import Path import mozpack.path as mozpath from mach.mixin.logging import LoggingMixin @@ -239,6 +242,72 @@ class BuildBackend(LoggingMixin): with open(mozpath.join(dir, ".purgecaches"), "w") as f: f.write("\n") + def _setup_tor_browser_environment(self, config): + app = config.substs["MOZ_BUILD_APP"] + + noscript_target_filename = "{73a6fe31-595d-460b-a920-fcc0f8843232}.xpi" + noscript_location = config.substs.get("NOSCRIPT") + + def _infallible_symlink(src, dst): + try: + os.symlink(src, dst) + except OSError as e: + if e.errno == errno.EEXIST: + # If the symlink already exists, remove it and try again. + os.remove(dst) + os.symlink(src, dst) + else: + return + + if app == "browser": + tbdir = Path(config.topobjdir) / "dist" / "bin" + + if config.substs.get("OS_TARGET") == "Darwin": + tbdir = next(tbdir.glob("*.app")) + paths = { + "docs": tbdir / "Contents/Resources/TorBrowser/Docs", + "exts": tbdir / "Contents/Resources/distribution/extensions", + "fonts": tbdir / "Resources/fonts", + } + else: + paths = { + "docs": tbdir / "TorBrowser/Docs", + "exts": tbdir / "distribution/extensions", + "fonts": tbdir / "fonts", + } + + fonts_location = config.substs.get("TOR_BROWSER_FONTS") + if fonts_location: + self.log( + logging.INFO, + "_setup_tor_browser_environment", + { + "fonts_location": fonts_location, + "fonts_target": str(paths["fonts"]), + }, + "Creating symlink for fonts files from {fonts_location} to {fonts_target}", + ) + + for file in Path(fonts_location).iterdir(): + target = paths["fonts"] / file.name + _infallible_symlink(file, target) + + # Set up NoScript extension + if noscript_location: + noscript_target = paths["exts"] / noscript_target_filename + self.log( + logging.INFO, + "_setup_tor_browser_environment", + { + "noscript_location": noscript_location, + "noscript_target": str(noscript_target), + }, + "Creating symlink for NoScript from {noscript_location} to {noscript_target}", + ) + + paths["exts"].mkdir(parents=True, exist_ok=True) + _infallible_symlink(noscript_location, noscript_target) + def post_build(self, config, output, jobs, verbose, status): """Called late during 'mach build' execution, after `build(...)` has finished. @@ -257,6 +326,9 @@ class BuildBackend(LoggingMixin): """ self._write_purgecaches(config) + if status == 0: + self._setup_tor_browser_environment(config) + return status @contextmanager ===================================== python/mozbuild/mozbuild/tbbutils.py ===================================== @@ -0,0 +1,103 @@ +import re +from urllib.request import Request, urlopen + + +def list_files_http(url): + try: + req = Request(url, method="GET") + with urlopen(req) as response: + if response.status != 200: + return [] + html = response.read().decode() + except Exception: + return [] + + links = [] + for href in re.findall(r'<a href="([^"]+)"', html): + if href == "../": + continue + + links.append(href) + + return links + + +TOR_BROWSER_BUILD_ARTIFACTS = [ + # Tor Browser Build-only artifacts, these artifacts are not common with Firefox. + "noscript", + "fonts", +] + +# Mapping of artifacts from taskcluster to tor-browser-build. +ARTIFACT_NAME_MAP = { + "cbindgen": "cbindgen", + # FIXME (tor-browser-build#41471): nasm is more or less ready to go, but it needs to have the + # executable in the root of the artifact folder instead of nasm/bin. + # "nasm": "nasm", + # FIXME (tor-browser-build#41421): the clang project as is, is not ready to use. It needs + # to be repackaged with a bunch of things that differ per platform. Fun stuff. + # "clang": "clang", + "node": "node", +} + + +def get_artifact_name(original_artifact_name, host): + # These are not build artifacts, they are pre-built artifacts to be added to the final build, + # therefore this check can come before the host check. + if original_artifact_name in TOR_BROWSER_BUILD_ARTIFACTS: + return original_artifact_name + + if host != "linux64": + # Tor browser build only has development artifacts for linux64 host systems. + return None + + return ARTIFACT_NAME_MAP.get(original_artifact_name) + + +def get_artifact_path(url, artifact, target, prefix="", log=lambda *args, **kwargs: {}): + if prefix: + path = prefix + else: + path = artifact + + # The `?C=M;O=D` parameters make it so links are ordered by + # the last modified date. This here to make us get the latest + # version of file in the case there are multiple and we just + # grab the first one. + files = list_files_http(f"{url}/{path}?C=M;O=D") + + if not files: + log(f"No files found in {url} for {artifact}.") + return None + + def filter_files(files, keyword): + return [file for file in files if keyword in file] + + artifact_files = [file for file in files if file.startswith(artifact)] + + if len(artifact_files) == 0: + log(f"No files found in {url} for {artifact}.") + return None + + if len(artifact_files) == 1: + return f"{url}/{path}/{artifact_files[0]}" + + files_per_os = filter_files(artifact_files, target.tor_browser_build_alias) + + # If there are files in the folder, but they don't have the OS in the name + # it probably means we can get any of them because they can be used to build + # for any OS. So let's just get the first one. + # + # Note: It could be the case that the artifact _is_ OS dependant, but there + # just are no files for the OS we are looking for. In that case, this will + # return an incorrect artifact. This should not happen often though and is + # something we cannot address until artifact names are standardized on tbb. + if len(files_per_os) == 0: + return f"{url}/{artifact}/{artifact_files[0]}" + + elif len(files_per_os) == 1: + return f"{url}/{artifact}/{files_per_os[0]}" + + matches = filter_files(files_per_os, target.cpu) + + return f"{url}/{artifact}/{matches[0]}" if matches else None ===================================== python/mozbuild/mozbuild/test/python.toml ===================================== @@ -111,6 +111,9 @@ subsuite = "mozbuild" ["test_rewrite_mozbuild.py"] +["test_tbbutils.py"] +subsuite = "base-browser" + ["test_telemetry.py"] ["test_telemetry_settings.py"] ===================================== python/mozbuild/mozbuild/test/test_tbbutils.py ===================================== @@ -0,0 +1,139 @@ +import unittest +from types import SimpleNamespace +from unittest.mock import MagicMock, patch + +import mozunit + +from mozbuild.tbbutils import get_artifact_path, list_files_http + + +class TestGetArtifactName(unittest.TestCase): + def setUp(self): + self.artifact = "artifact" + self.host = "linux64" + + @patch("mozbuild.tbbutils.TOR_BROWSER_BUILD_ARTIFACTS", new=["artifact"]) + def test_artifact_in_tbb_artifacts(self): + from mozbuild.tbbutils import get_artifact_name + + result = get_artifact_name(self.artifact, self.host) + self.assertEqual(result, self.artifact) + + @patch("mozbuild.tbbutils.ARTIFACT_NAME_MAP", new={"artifact": "tcafitra"}) + def test_host_is_not_linux64(self): + from mozbuild.tbbutils import get_artifact_name + + result = get_artifact_name(self.artifact, "linux64-aarch64") + self.assertIsNone(result) + + @patch("mozbuild.tbbutils.ARTIFACT_NAME_MAP", new={"artifact": "tcafitra"}) + def test_mapped_artifact(self): + from mozbuild.tbbutils import get_artifact_name + + result = get_artifact_name(self.artifact, self.host) + self.assertEqual(result, self.artifact[::-1]) + + +class TestGetArtifactPath(unittest.TestCase): + def setUp(self): + self.url = "http://example.com" + self.artifact = "artifact" + # This is just an example target which is valid. But it doesn't make + # any difference and could be anything for these tests. + self.target = SimpleNamespace(tor_browser_build_alias="linux", cpu="x86_64") + + @patch("mozbuild.tbbutils.list_files_http") + def test_no_files_returns_none(self, mock_list_files): + mock_list_files.return_value = [] + result = get_artifact_path(self.url, self.artifact, self.target) + self.assertIsNone(result) + + @patch("mozbuild.tbbutils.list_files_http") + def test_no_matching_files_returns_none(self, mock_list_files): + mock_list_files.return_value = ["somethingelse.zip", "yetanotherthing.zip"] + result = get_artifact_path(self.url, self.artifact, self.target) + self.assertIsNone(result) + + @patch("mozbuild.tbbutils.list_files_http") + def test_single_artifact_match(self, mock_list_files): + mock_list_files.return_value = ["artifact-1.zip"] + result = get_artifact_path(self.url, self.artifact, self.target) + self.assertEqual(result, f"{self.url}/{self.artifact}/artifact-1.zip") + + @patch("mozbuild.tbbutils.list_files_http") + def test_artifact_without_os_returns_first(self, mock_list_files): + mock_list_files.return_value = ["artifact-1.zip", "artifact-2.zip"] + result = get_artifact_path(self.url, self.artifact, self.target) + self.assertTrue(result.startswith(f"{self.url}/{self.artifact}/")) + self.assertIn("artifact-", result) + + @patch("mozbuild.tbbutils.list_files_http") + def test_artifact_with_os_match(self, mock_list_files): + mock_list_files.return_value = [ + "artifact-windows.zip", + "artifact-linux.zip", + ] + result = get_artifact_path(self.url, self.artifact, self.target) + self.assertEqual(result, f"{self.url}/{self.artifact}/artifact-linux.zip") + + @patch("mozbuild.tbbutils.list_files_http") + def test_artifact_with_cpu_match(self, mock_list_files): + mock_list_files.return_value = [ + "artifact-linux-arm.zip", + "artifact-linux-x86_64.zip", + ] + result = get_artifact_path(self.url, self.artifact, self.target) + self.assertEqual( + result, f"{self.url}/{self.artifact}/artifact-linux-x86_64.zip" + ) + + @patch("mozbuild.tbbutils.list_files_http") + def test_artifact_with_prefix(self, mock_list_files): + mock_list_files.return_value = ["artifact-1.zip"] + + prefix = "prefix" + result = get_artifact_path(self.url, self.artifact, self.target, prefix=prefix) + self.assertEqual(result, f"{self.url}/{prefix}/artifact-1.zip") + mock_list_files.assert_called_with(f"{self.url}/{prefix}?C=M;O=D") + + +class TestListFilesHttp(unittest.TestCase): + def setUp(self): + self.url = "http://example.com" + + @patch("mozbuild.tbbutils.urlopen") + def test_non_200_status_returns_empty(self, mock_urlopen): + mock_resp = MagicMock() + mock_resp.status = 404 + mock_resp.read.return_value = b"" + mock_urlopen.return_value.__enter__.return_value = mock_resp + + result = list_files_http(self.url) + self.assertEqual(result, []) + + @patch("mozbuild.tbbutils.urlopen") + def test_exception_returns_empty(self, mock_urlopen): + mock_urlopen.side_effect = Exception("network error") + result = list_files_http(self.url) + self.assertEqual(result, []) + + @patch("mozbuild.tbbutils.urlopen") + def test_regular_links(self, mock_urlopen): + html = b""" + <html><body> + <a href="../">Parent</a> + <a href="file1.zip">file1</a> + <a href="file2.zip">file2</a> + </body></html> + """ + mock_resp = MagicMock() + mock_resp.status = 200 + mock_resp.read.return_value = html + mock_urlopen.return_value.__enter__.return_value = mock_resp + + result = list_files_http(self.url) + self.assertEqual(result, ["file1.zip", "file2.zip"]) + + +if __name__ == "__main__": + mozunit.main() ===================================== tools/base-browser/l10n/combine/tests/README deleted ===================================== @@ -1,2 +0,0 @@ -python tests to be run with pytest. -Requires the compare-locales package. ===================================== tools/base-browser/git-rebase-fixup-preprocessor → tools/base_browser/git-rebase-fixup-preprocessor ===================================== ===================================== tools/base-browser/l10n/combine-translation-versions.py → tools/base_browser/l10n/combine-translation-versions.py ===================================== ===================================== tools/base-browser/l10n/combine/__init__.py → tools/base_browser/l10n/combine/__init__.py ===================================== ===================================== tools/base-browser/l10n/combine/combine.py → tools/base_browser/l10n/combine/combine.py ===================================== ===================================== tools/base-browser/l10n/combine/tests/__init__.py → tools/base_browser/l10n/combine/tests/__init__.py ===================================== ===================================== tools/base_browser/l10n/combine/tests/python.toml ===================================== @@ -0,0 +1,10 @@ +[DEFAULT] +subsuite = "base-browser" + +["test_android.py"] + +["test_dtd.py"] + +["test_fluent.py"] + +["test_properties.py"] ===================================== tools/base-browser/l10n/combine/tests/test_android.py → tools/base_browser/l10n/combine/tests/test_android.py ===================================== @@ -1,6 +1,7 @@ import textwrap -from combine import combine_files +import mozunit +from base_browser.l10n.combine import combine_files def wrap_in_xml(content): @@ -413,3 +414,7 @@ def test_alternatives(): <string name="string_4_alt">Other string</string> """, ) + + +if __name__ == "__main__": + mozunit.main() ===================================== tools/base-browser/l10n/combine/tests/test_dtd.py → tools/base_browser/l10n/combine/tests/test_dtd.py ===================================== @@ -1,6 +1,7 @@ import textwrap -from combine import combine_files +import mozunit +from base_browser.l10n.combine import combine_files def assert_result(new_content, old_content, expect): @@ -411,3 +412,7 @@ def test_alternatives(): <!ENTITY string.4.alt "Other string"> """, ) + + +if __name__ == "__main__": + mozunit.main() ===================================== tools/base-browser/l10n/combine/tests/test_fluent.py → tools/base_browser/l10n/combine/tests/test_fluent.py ===================================== @@ -1,6 +1,7 @@ import textwrap -from combine import combine_files +import mozunit +from base_browser.l10n.combine import combine_files def assert_result(new_content, old_content, expect): @@ -475,3 +476,7 @@ def test_alternatives(): -string-4-alt = Other string """, ) + + +if __name__ == "__main__": + mozunit.main() ===================================== tools/base-browser/l10n/combine/tests/test_properties.py → tools/base_browser/l10n/combine/tests/test_properties.py ===================================== @@ -1,6 +1,7 @@ import textwrap -from combine import combine_files +import mozunit +from base_browser.l10n.combine import combine_files def assert_result(new_content, old_content, expect): @@ -408,3 +409,7 @@ def test_alternatives(): string.4.alt = Other string """, ) + + +if __name__ == "__main__": + mozunit.main() ===================================== tools/base-browser/missing-css-variables.py → tools/base_browser/missing-css-variables.py ===================================== ===================================== tools/base-browser/tb-dev → tools/base_browser/tb-dev ===================================== ===================================== tools/moz.build ===================================== @@ -71,6 +71,7 @@ with Files("tryselect/docs/**"): SCHEDULES.exclusive = ["docs"] PYTHON_UNITTEST_MANIFESTS += [ + "base_browser/l10n/combine/tests/python.toml", "fuzzing/smoke/python.toml", "lint/test/python.toml", "tryselect/test/python.toml", View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/53201c… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/53201c… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][tor-browser-140.2.0esr-15.0-1] fixup! BB 43564: Modify ./mach bootstrap for Base Browser
by brizental (@brizental) 08 Sep '25

08 Sep '25
brizental pushed to branch tor-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser Commits: e3afce24 by Beatriz Rizental at 2025-09-08T18:43:45+02:00 fixup! BB 43564: Modify ./mach bootstrap for Base Browser - - - - - 3 changed files: - build/moz.configure/bootstrap.configure - python/mozbuild/mozbuild/tbbutils.py - python/mozbuild/mozbuild/test/test_tbbutils.py Changes: ===================================== build/moz.configure/bootstrap.configure ===================================== @@ -211,7 +211,11 @@ def bootstrap_path(path, **kwargs): return False artifact_path = mozbuild.tbbutils.get_artifact_path( - tor_browser_build_out, artifact, target, prefix=path_prefix + tor_browser_build_out, + artifact, + target, + prefix=path_prefix, + log=log.warning, ) if not artifact_path: log.info("no path found in tbb/out for %s", artifact) ===================================== python/mozbuild/mozbuild/tbbutils.py ===================================== @@ -58,7 +58,7 @@ def get_artifact_name(original_artifact_name, host): return ARTIFACT_NAME_MAP.get(original_artifact_name) -def get_artifact_path(url, artifact, target, prefix=""): +def get_artifact_path(url, artifact, target, prefix="", log=lambda *args, **kwargs: {}): if prefix: path = prefix else: @@ -71,6 +71,7 @@ def get_artifact_path(url, artifact, target, prefix=""): files = list_files_http(f"{url}/{path}?C=M;O=D") if not files: + log(f"No files found in {url} for {artifact}.") return None def filter_files(files, keyword): @@ -78,6 +79,10 @@ def get_artifact_path(url, artifact, target, prefix=""): artifact_files = [file for file in files if file.startswith(artifact)] + if len(artifact_files) == 0: + log(f"No files found in {url} for {artifact}.") + return None + if len(artifact_files) == 1: return f"{url}/{path}/{artifact_files[0]}" ===================================== python/mozbuild/mozbuild/test/test_tbbutils.py ===================================== @@ -48,6 +48,12 @@ class TestGetArtifactPath(unittest.TestCase): result = get_artifact_path(self.url, self.artifact, self.target) self.assertIsNone(result) + @patch("mozbuild.tbbutils.list_files_http") + def test_no_matching_files_returns_none(self, mock_list_files): + mock_list_files.return_value = ["somethingelse.zip", "yetanotherthing.zip"] + result = get_artifact_path(self.url, self.artifact, self.target) + self.assertIsNone(result) + @patch("mozbuild.tbbutils.list_files_http") def test_single_artifact_match(self, mock_list_files): mock_list_files.return_value = ["artifact-1.zip"] View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/e3afce2… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/e3afce2… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/mullvad-browser][mullvad-browser-140.2.0esr-15.0-1] fixup! MB 419: Mullvad Browser migration procedures.
by Pier Angelo Vendrame (@pierov) 08 Sep '25

08 Sep '25
Pier Angelo Vendrame pushed to branch mullvad-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Mullvad Browser Commits: a5709ed4 by Pier Angelo Vendrame at 2025-09-08T16:07:32+02:00 fixup! MB 419: Mullvad Browser migration procedures. BB 43770: Follow upstream's BrowserGlue simplifications. - - - - - 2 changed files: - browser/components/BrowserGlue.sys.mjs - browser/components/ProfileDataUpgrader.sys.mjs Changes: ===================================== browser/components/BrowserGlue.sys.mjs ===================================== @@ -430,9 +430,7 @@ BrowserGlue.prototype = { // handle any UI migration this._migrateUI(); lazy.ProfileDataUpgrader.upgradeBB(this._isNewProfile); - - // Mullvad Browser-specific version of _migrateUI. - this._migrateUIMB(); + lazy.ProfileDataUpgrader.upgradeMB(this._isNewProfile); if (!Services.prefs.prefHasUserValue(PREF_PDFJS_ISDEFAULT_CACHE_STATE)) { lazy.PdfJs.checkIsDefault(this._isNewProfile); @@ -1654,58 +1652,6 @@ BrowserGlue.prototype = { } }, - // Use this method for any MB migration that can be run just before showing - // the UI. - // Anything that critically needs to be migrated earlier should not use this. - async _migrateUIMB() { - // Version 1: Mullvad Browser 14.5a6: Clear home page update url preference - // (mullvad-browser#411). - // Version 2: Mullvad Browser 15.0a2: Remove legacy search addons - // (tor-browser#43111). - const MB_MIGRATION_VERSION = 2; - const MIGRATION_PREF = "mullvadbrowser.migration.version"; - - // If we decide to force updating users to pass through any version - // following 14.5, we can remove this check, and check only whether - // MIGRATION_PREF has a user value, like Mozilla does. - if (this._isNewProfile) { - // Do not migrate fresh profiles - Services.prefs.setIntPref(MIGRATION_PREF, MB_MIGRATION_VERSION); - return; - } else if (this._isNewProfile === undefined) { - // If this happens, check if upstream updated their function and do not - // set this member anymore! - console.error("_migrateUIMB: this._isNewProfile is undefined."); - } - - const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0); - - if (currentVersion < 1) { - Services.prefs.clearUserPref("mullvadbrowser.post_update.url"); - } - const dropAddons = async list => { - for (const id of list) { - try { - const engine = await lazy.AddonManager.getAddonByID(id); - await engine?.uninstall(); - } catch {} - } - }; - if (currentVersion < 2) { - await dropAddons([ - "brave(a)search.mozilla.org", - "ddg(a)search.mozilla.org", - "ddg-html(a)search.mozilla.org", - "metager(a)search.mozilla.org", - "mojeek(a)search.mozilla.org", - "mullvad-leta(a)search.mozilla.org", - "startpage(a)search.mozilla.org", - ]); - } - - Services.prefs.setIntPref(MIGRATION_PREF, MB_MIGRATION_VERSION); - }, - async _showUpgradeDialog() { const data = await lazy.OnboardingMessageProvider.getUpgradeMessage(); const { gBrowser } = lazy.BrowserWindowTracker.getTopWindow(); ===================================== browser/components/ProfileDataUpgrader.sys.mjs ===================================== @@ -974,4 +974,50 @@ export let ProfileDataUpgrader = { } Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); }, + + async upgradeMB(isNewProfile) { + // Version 1: Mullvad Browser 14.5a6: Clear home page update url preference + // (mullvad-browser#411). + // Version 2: Mullvad Browser 15.0a2: Remove legacy search addons + // (tor-browser#43111). + const MB_MIGRATION_VERSION = 2; + const MIGRATION_PREF = "mullvadbrowser.migration.version"; + + if (isNewProfile) { + // Do not migrate fresh profiles + Services.prefs.setIntPref(MIGRATION_PREF, MB_MIGRATION_VERSION); + return; + } else if (isNewProfile === undefined) { + // If this happens, check if upstream updated their function and do not + // set this member anymore! + console.error("upgradeTB: isNewProfile is undefined."); + } + + const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0); + + if (currentVersion < 1) { + Services.prefs.clearUserPref("mullvadbrowser.post_update.url"); + } + const dropAddons = async list => { + for (const id of list) { + try { + const engine = await lazy.AddonManager.getAddonByID(id); + await engine?.uninstall(); + } catch {} + } + }; + if (currentVersion < 2) { + await dropAddons([ + "brave(a)search.mozilla.org", + "ddg(a)search.mozilla.org", + "ddg-html(a)search.mozilla.org", + "metager(a)search.mozilla.org", + "mojeek(a)search.mozilla.org", + "mullvad-leta(a)search.mozilla.org", + "startpage(a)search.mozilla.org", + ]); + } + + Services.prefs.setIntPref(MIGRATION_PREF, MB_MIGRATION_VERSION); + }, }; View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/a57… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/a57… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][tor-browser-140.2.0esr-15.0-1] fixup! TB 43006: Disable RFP for Font Visibility on Android
by morgan (@morgan) 08 Sep '25

08 Sep '25
morgan pushed to branch tor-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser Commits: dc42afa4 by Pier Angelo Vendrame at 2025-09-08T13:51:04+00:00 fixup! TB 43006: Disable RFP for Font Visibility on Android TB 43943: Refactor fontvis exclusion on Android. Rather than updating Document, we can use nsRFPService::HandleExeptionalRFPTargets. - - - - - 2 changed files: - dom/base/Document.cpp - toolkit/components/resistfingerprinting/nsRFPService.cpp Changes: ===================================== dom/base/Document.cpp ===================================== @@ -17308,12 +17308,6 @@ bool Document::RecomputeResistFingerprinting(bool aForceRefreshRTPCallerType) { } bool Document::ShouldResistFingerprinting(RFPTarget aTarget) const { -#ifdef ANDROID - if (aTarget == RFPTarget::FontVisibilityBaseSystem || - aTarget == RFPTarget::FontVisibilityLangPack) { - return false; - } -#endif return mShouldResistFingerprinting && nsRFPService::IsRFPEnabledFor(this->IsInPrivateBrowsing(), aTarget, mOverriddenFingerprintingSettings); ===================================== toolkit/components/resistfingerprinting/nsRFPService.cpp ===================================== @@ -310,6 +310,13 @@ Maybe<bool> nsRFPService::HandleExeptionalRFPTargets( } #endif +#ifdef ANDROID + if (aTarget == RFPTarget::FontVisibilityBaseSystem || + aTarget == RFPTarget::FontVisibilityLangPack) { + return Some(false); + } +#endif + return Nothing(); } View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/dc42afa… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/dc42afa… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/mullvad-browser][mullvad-browser-140.2.0esr-15.0-1] fixup! Firefox preference overrides.
by Pier Angelo Vendrame (@pierov) 08 Sep '25

08 Sep '25
Pier Angelo Vendrame pushed to branch mullvad-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Mullvad Browser Commits: c735c7ed by Pier Angelo Vendrame at 2025-09-08T15:51:22+02:00 fixup! Firefox preference overrides. BB 43950: Disable HEVC. HEVC support can be used for fingerprinting, as it's hardware-dependent on some systems, or depends on distribution support/installed packages for Linux. - - - - - 1 changed file: - browser/app/profile/001-base-profile.js Changes: ===================================== browser/app/profile/001-base-profile.js ===================================== @@ -483,6 +483,9 @@ pref("gfx.offscreencanvas.enabled", false); pref("dom.disable_window_move_resize", true); // Set video VP9 to 0 for everyone (bug 22548) pref("media.benchmark.vp9.threshold", 0); +// tor-browser#43950: Disable HEVC, as it will reveal lacking hardware support, +// or differences in installed codec for Linux systems. +pref("media.hevc.enabled", false); pref("privacy.resistFingerprinting.block_mozAddonManager", true); // Bug 26114 pref("dom.webmidi.enabled", false); // Bug 41398: Disable Web MIDI API // tor-browser#42043: Stop reporting device IDs (and spoof their number without View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/c73… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/c73… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][base-browser-140.2.0esr-15.0-1] fixup! Firefox preference overrides.
by Pier Angelo Vendrame (@pierov) 08 Sep '25

08 Sep '25
Pier Angelo Vendrame pushed to branch base-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser Commits: 53201cbe by Pier Angelo Vendrame at 2025-09-08T15:49:55+02:00 fixup! Firefox preference overrides. BB 43950: Disable HEVC. HEVC support can be used for fingerprinting, as it's hardware-dependent on some systems, or depends on distribution support/installed packages for Linux. - - - - - 1 changed file: - browser/app/profile/001-base-profile.js Changes: ===================================== browser/app/profile/001-base-profile.js ===================================== @@ -483,6 +483,9 @@ pref("gfx.offscreencanvas.enabled", false); pref("dom.disable_window_move_resize", true); // Set video VP9 to 0 for everyone (bug 22548) pref("media.benchmark.vp9.threshold", 0); +// tor-browser#43950: Disable HEVC, as it will reveal lacking hardware support, +// or differences in installed codec for Linux systems. +pref("media.hevc.enabled", false); pref("privacy.resistFingerprinting.block_mozAddonManager", true); // Bug 26114 pref("dom.webmidi.enabled", false); // Bug 41398: Disable Web MIDI API // tor-browser#42043: Stop reporting device IDs (and spoof their number without View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/53201cb… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/53201cb… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][tor-browser-140.2.0esr-15.0-1] fixup! Firefox preference overrides.
by Pier Angelo Vendrame (@pierov) 08 Sep '25

08 Sep '25
Pier Angelo Vendrame pushed to branch tor-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser Commits: c02477fa by Pier Angelo Vendrame at 2025-09-08T13:44:13+00:00 fixup! Firefox preference overrides. BB 43950: Disable HEVC. HEVC support can be used for fingerprinting, as it's hardware-dependent on some systems, or depends on distribution support/installed packages for Linux. - - - - - 1 changed file: - browser/app/profile/001-base-profile.js Changes: ===================================== browser/app/profile/001-base-profile.js ===================================== @@ -483,6 +483,9 @@ pref("gfx.offscreencanvas.enabled", false); pref("dom.disable_window_move_resize", true); // Set video VP9 to 0 for everyone (bug 22548) pref("media.benchmark.vp9.threshold", 0); +// tor-browser#43950: Disable HEVC, as it will reveal lacking hardware support, +// or differences in installed codec for Linux systems. +pref("media.hevc.enabled", false); pref("privacy.resistFingerprinting.block_mozAddonManager", true); // Bug 26114 pref("dom.webmidi.enabled", false); // Bug 41398: Disable Web MIDI API // tor-browser#42043: Stop reporting device IDs (and spoof their number without View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/c02477f… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/c02477f… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/mullvad-browser][mullvad-browser-140.2.0esr-15.0-1] 3 commits: fixup! BB 42019: Empty browser's clipboard on browser shutdown
by Pier Angelo Vendrame (@pierov) 08 Sep '25

08 Sep '25
Pier Angelo Vendrame pushed to branch mullvad-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Mullvad Browser Commits: 4c83f2db by Pier Angelo Vendrame at 2025-09-08T12:32:21+02:00 fixup! BB 42019: Empty browser's clipboard on browser shutdown BB 43770: Follow upstream's BrowserGlue simplifications. ClipboardPrivacy to its own file and initialize it from the manifest, rather than from BrowserGlue. - - - - - 4b7d805c by Pier Angelo Vendrame at 2025-09-08T12:32:32+02:00 fixup! BB 40925: Implemented the Security Level component BB 43770: Follow upstream's BrowserGlue simplifications. Initialize the security level notification from the manifest. Also, since it was the only occurrence of the file path, move it to the moz-src:// scheme. - - - - - 7a6cc7a1 by Pier Angelo Vendrame at 2025-09-08T12:35:10+02:00 fixup! BB 42027: Base Browser migration procedures. BB 43770: Follow upstream's BrowserGlue simplifications. - - - - - 5 changed files: - browser/components/BrowserComponents.manifest - browser/components/BrowserGlue.sys.mjs - browser/components/ProfileDataUpgrader.sys.mjs - + browser/modules/ClipboardPrivacy.sys.mjs - browser/modules/moz.build Changes: ===================================== browser/components/BrowserComponents.manifest ===================================== @@ -50,6 +50,8 @@ category browser-first-window-ready resource://gre/modules/CaptchaDetectionPingU category browser-first-window-ready resource://gre/modules/SandboxUtils.sys.mjs SandboxUtils.maybeWarnAboutMissingUserNamespaces #endif #endif +category browser-first-window-ready moz-src:///browser/modules/ClipboardPrivacy.sys.mjs ClipboardPrivacy.init +category browser-first-window-ready moz-src:///browser/modules/SecurityLevelRestartNotification.sys.mjs SecurityLevelRestartNotification.ready category browser-idle-startup resource:///modules/PlacesUIUtils.sys.mjs PlacesUIUtils.unblockToolbars category browser-idle-startup resource:///modules/BuiltInThemes.sys.mjs BuiltInThemes.ensureBuiltInThemes ===================================== browser/components/BrowserGlue.sys.mjs ===================================== @@ -12,7 +12,6 @@ ChromeUtils.defineESModuleGetters(lazy, { AWToolbarButton: "resource:///modules/aboutwelcome/AWToolbarUtils.sys.mjs", ASRouter: "resource:///modules/asrouter/ASRouter.sys.mjs", AddonManager: "resource://gre/modules/AddonManager.sys.mjs", - AsyncShutdown: "resource://gre/modules/AsyncShutdown.sys.mjs", BackupService: "resource:///modules/backup/BackupService.sys.mjs", BrowserSearchTelemetry: "moz-src:///browser/components/search/BrowserSearchTelemetry.sys.mjs", @@ -61,8 +60,6 @@ ChromeUtils.defineESModuleGetters(lazy, { ScreenshotsUtils: "resource:///modules/ScreenshotsUtils.sys.mjs", SearchSERPTelemetry: "moz-src:///browser/components/search/SearchSERPTelemetry.sys.mjs", - SecurityLevelRestartNotification: - "resource:///modules/SecurityLevelRestartNotification.sys.mjs", SessionStartup: "resource:///modules/sessionstore/SessionStartup.sys.mjs", SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs", ShortcutUtils: "resource://gre/modules/ShortcutUtils.sys.mjs", @@ -106,170 +103,6 @@ if (AppConstants.ENABLE_WEBDRIVER) { const PREF_PDFJS_ISDEFAULT_CACHE_STATE = "pdfjs.enabledCache.state"; -// Empty clipboard content from private windows on exit -// (tor-browser#42154) -const ClipboardPrivacy = { - _lastClipboardHash: null, - _globalActivation: false, - _isPrivateClipboard: false, - _hasher: null, - _shuttingDown: false, - _log: null, - - _createTransferable() { - const trans = Cc["@mozilla.org/widget/transferable;1"].createInstance( - Ci.nsITransferable - ); - trans.init(null); - return trans; - }, - _computeClipboardHash() { - const flavors = ["text/x-moz-url", "text/plain"]; - if ( - !Services.clipboard.hasDataMatchingFlavors( - flavors, - Ci.nsIClipboard.kGlobalClipboard - ) - ) { - return null; - } - const trans = this._createTransferable(); - flavors.forEach(trans.addDataFlavor); - try { - Services.clipboard.getData(trans, Ci.nsIClipboard.kGlobalClipboard); - const clipboardContent = {}; - trans.getAnyTransferData({}, clipboardContent); - const { data } = clipboardContent.value.QueryInterface( - Ci.nsISupportsString - ); - const bytes = new TextEncoder().encode(data); - const hasher = (this._hasher ||= Cc[ - "@mozilla.org/security/hash;1" - ].createInstance(Ci.nsICryptoHash)); - hasher.init(hasher.SHA256); - hasher.update(bytes, bytes.length); - return hasher.finish(true); - } catch (e) {} - return null; - }, - - startup() { - this._log = console.createInstance({ - prefix: "ClipboardPrivacy", - }); - this._lastClipboardHash = this._computeClipboardHash(); - - // Here we track changes in active window / application, - // by filtering focus events and window closures. - const handleActivation = (win, activation) => { - if (activation) { - if (!this._globalActivation) { - // focus changed within this window, bail out. - return; - } - this._globalActivation = false; - } else if (!Services.focus.activeWindow) { - // focus is leaving this window: - // let's track whether it remains within the browser. - lazy.setTimeout(() => { - this._globalActivation = !Services.focus.activeWindow; - }, 100); - } - - const checkClipboardContent = () => { - const clipboardHash = this._computeClipboardHash(); - if (clipboardHash !== this._lastClipboardHash) { - this._isPrivateClipboard = - !activation && - (lazy.PrivateBrowsingUtils.permanentPrivateBrowsing || - lazy.PrivateBrowsingUtils.isWindowPrivate(win)); - this._lastClipboardHash = clipboardHash; - this._log.debug( - `Clipboard changed: private ${this._isPrivateClipboard}, hash ${clipboardHash}.` - ); - } - }; - - if (win.closed) { - checkClipboardContent(); - } else { - // defer clipboard access on DOM events to work-around tor-browser#42306 - lazy.setTimeout(checkClipboardContent, 0); - } - }; - const focusListener = e => - e.isTrusted && handleActivation(e.currentTarget, e.type === "focusin"); - const initWindow = win => { - for (const e of ["focusin", "focusout"]) { - win.addEventListener(e, focusListener); - } - }; - for (const w of Services.ww.getWindowEnumerator()) { - initWindow(w); - } - Services.ww.registerNotification((win, event) => { - switch (event) { - case "domwindowopened": - initWindow(win); - break; - case "domwindowclosed": - handleActivation(win, false); - if ( - this._isPrivateClipboard && - lazy.PrivateBrowsingUtils.isWindowPrivate(win) && - (this._shuttingDown || - !Array.from(Services.ww.getWindowEnumerator()).find( - w => - lazy.PrivateBrowsingUtils.isWindowPrivate(w) && - // We need to filter out the HIDDEN WebExtensions window, - // which might be private as well but is not UI-relevant. - !w.location.href.startsWith("chrome://extensions/") - )) - ) { - // no more private windows, empty private content if needed - this.emptyPrivate(); - } - } - }); - - lazy.AsyncShutdown.quitApplicationGranted.addBlocker( - "ClipboardPrivacy: removing private data", - () => { - this._shuttingDown = true; - this.emptyPrivate(); - } - ); - }, - emptyPrivate() { - if ( - this._isPrivateClipboard && - !Services.prefs.getBoolPref( - "browser.privatebrowsing.preserveClipboard", - false - ) && - this._lastClipboardHash === this._computeClipboardHash() - ) { - // nsIClipboard.emptyClipboard() does nothing in Wayland: - // we'll set an empty string as a work-around. - const trans = this._createTransferable(); - const flavor = "text/plain"; - trans.addDataFlavor(flavor); - const emptyString = Cc["@mozilla.org/supports-string;1"].createInstance( - Ci.nsISupportsString - ); - emptyString.data = ""; - trans.setTransferData(flavor, emptyString); - const { clipboard } = Services, - { kGlobalClipboard } = clipboard; - clipboard.setData(trans, null, kGlobalClipboard); - clipboard.emptyClipboard(kGlobalClipboard); - this._lastClipboardHash = null; - this._isPrivateClipboard = false; - this._log.info("Private clipboard emptied."); - } - }, -}; - ChromeUtils.defineLazyGetter( lazy, "WeaveService", @@ -596,9 +429,7 @@ BrowserGlue.prototype = { // handle any UI migration this._migrateUI(); - - // Base Browser-specific version of _migrateUI. - this._migrateUIBB(); + lazy.ProfileDataUpgrader.upgradeBB(this._isNewProfile); // Mullvad Browser-specific version of _migrateUI. this._migrateUIMB(); @@ -987,10 +818,6 @@ BrowserGlue.prototype = { lazy.WeaveService.init(); } - lazy.SecurityLevelRestartNotification.ready(); - - ClipboardPrivacy.startup(); - lazy.BrowserUtils.callModulesFromCategory( { categoryName: "browser-first-window-ready", @@ -1827,83 +1654,6 @@ BrowserGlue.prototype = { } }, - _migrateUIBB() { - // Version 1: 13.0a3. Reset layout.css.prefers-color-scheme.content-override - // for tor-browser#41739. - // Version 2: 14.0a5: Reset the privacy tracking headers preferences since - // the UI is hidden. tor-browser#42777. - // Also, do not set - // dom.security.https_only_mode_send_http_background_request in - // the security level anymore (tor-browser#42149). - // Also, reset security.xfocsp.errorReporting.automatic since we - // hid its neterror checkbox. tor-browser#42653. - // Version 3: 14.0a7: Reset general.smoothScroll. tor-browser#42070. - // Version 4: 15.0a2: Drop ML components. tor-browser#44045. - const MIGRATION_VERSION = 4; - const MIGRATION_PREF = "basebrowser.migration.version"; - if (this._isNewProfile) { - // Do not migrate fresh profiles - Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); - return; - } else if (this._isNewProfile === undefined) { - // If this happens, check if upstream updated their function and do not - // set this member anymore! - console.error("_migrateUIBB: this._isNewProfile is undefined."); - } - // We do not care whether this is a new or old profile, since in version 1 - // we just quickly clear a user preference, which should not do anything to - // new profiles. - // Shall we ever raise the version number and have a watershed, we can add - // a check easily (any version > 0 will be an old profile). - const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0); - if (currentVersion < 1) { - Services.prefs.clearUserPref( - "layout.css.prefers-color-scheme.content-override" - ); - } - if (currentVersion < 2) { - for (const prefName of [ - "privacy.globalprivacycontrol.enabled", - "privacy.donottrackheader.enabled", - // Telemetry preference for if the user changed the value. - "privacy.globalprivacycontrol.was_ever_enabled", - // The next two preferences have no corresponding UI, but are related. - "privacy.globalprivacycontrol.functionality.enabled", - "privacy.globalprivacycontrol.pbmode.enabled", - "dom.security.https_only_mode_send_http_background_request", - "security.xfocsp.errorReporting.automatic", - ]) { - Services.prefs.clearUserPref(prefName); - } - } - if (currentVersion < 3) { - Services.prefs.clearUserPref("general.smoothScroll"); - } - if (currentVersion < 4) { - for (const prefName of [ - "browser.translations.enable", - "browser.ml.enable", - "browser.ml.chat.enabled", - "browser.ml.linkPreview.enabled", - "browser.tabs.groups.smart.enabled", - "browser.tabs.groups.smart.userEnabled", - "extensions.ml.enabled", - "pdfjs.enableAltText", - "pdfjs.enableAltTextForEnglish", - "pdfjs.enableGuessAltText", - "pdfjs.enableAltTextModelDownload", - "browser.urlbar.quicksuggest.mlEnabled", - "places.semanticHistory.featureGate", - ]) { - // Preferences are locked. Do not want user values to linger in the - // user's profile and become active if these preferences become unlocked - // in the future. - Services.prefs.clearUserPref(prefName); - } - } - Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); - }, - // Use this method for any MB migration that can be run just before showing // the UI. // Anything that critically needs to be migrated earlier should not use this. ===================================== browser/components/ProfileDataUpgrader.sys.mjs ===================================== @@ -900,4 +900,78 @@ export let ProfileDataUpgrader = { // Update the migration version. Services.prefs.setIntPref("browser.migration.version", newVersion); }, + + upgradeBB(isNewProfile) { + // Version 1: 13.0a3. Reset layout.css.prefers-color-scheme.content-override + // for tor-browser#41739. + // Version 2: 14.0a5: Reset the privacy tracking headers preferences since + // the UI is hidden. tor-browser#42777. + // Also, do not set + // dom.security.https_only_mode_send_http_background_request in + // the security level anymore (tor-browser#42149). + // Also, reset security.xfocsp.errorReporting.automatic since we + // hid its neterror checkbox. tor-browser#42653. + // Version 3: 14.0a7: Reset general.smoothScroll. tor-browser#42070. + // Version 4: 15.0a2: Drop ML components. tor-browser#44045. + const MIGRATION_VERSION = 4; + const MIGRATION_PREF = "basebrowser.migration.version"; + + if (isNewProfile) { + // Do not migrate fresh profiles + Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); + return; + } else if (isNewProfile === undefined) { + // If this happens, check if upstream updated their function and do not + // set this member anymore! + console.error("upgradeBB: isNewProfile is undefined."); + } + + const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0); + if (currentVersion < 1) { + Services.prefs.clearUserPref( + "layout.css.prefers-color-scheme.content-override" + ); + } + if (currentVersion < 2) { + for (const prefName of [ + "privacy.globalprivacycontrol.enabled", + "privacy.donottrackheader.enabled", + // Telemetry preference for if the user changed the value. + "privacy.globalprivacycontrol.was_ever_enabled", + // The next two preferences have no corresponding UI, but are related. + "privacy.globalprivacycontrol.functionality.enabled", + "privacy.globalprivacycontrol.pbmode.enabled", + "dom.security.https_only_mode_send_http_background_request", + "security.xfocsp.errorReporting.automatic", + ]) { + Services.prefs.clearUserPref(prefName); + } + } + if (currentVersion < 3) { + Services.prefs.clearUserPref("general.smoothScroll"); + } + if (currentVersion < 4) { + for (const prefName of [ + "browser.translations.enable", + "browser.ml.enable", + "browser.ml.chat.enabled", + "browser.ml.linkPreview.enabled", + "browser.tabs.groups.smart.enabled", + "browser.tabs.groups.smart.userEnabled", + "extensions.ml.enabled", + "pdfjs.enableAltText", + "pdfjs.enableAltTextForEnglish", + "pdfjs.enableGuessAltText", + "pdfjs.enableAltTextModelDownload", + "browser.urlbar.quicksuggest.mlEnabled", + "places.semanticHistory.featureGate", + ]) { + // Preferences are locked. Do not want user values to linger in the + // user's profile and become active if these preferences become unlocked + // in the future. + Services.prefs.clearUserPref(prefName); + } + } + Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); + }, }; ===================================== browser/modules/ClipboardPrivacy.sys.mjs ===================================== @@ -0,0 +1,178 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + AsyncShutdown: "resource://gre/modules/AsyncShutdown.sys.mjs", + PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", + setTimeout: "resource://gre/modules/Timer.sys.mjs", +}); + +/** + * Empty clipboard content from private windows on exit. + * + * See tor-browser#42154. + */ +export const ClipboardPrivacy = { + _lastClipboardHash: null, + _globalActivation: false, + _isPrivateClipboard: false, + _hasher: null, + _shuttingDown: false, + _log: null, + + _createTransferable() { + const trans = Cc["@mozilla.org/widget/transferable;1"].createInstance( + Ci.nsITransferable + ); + trans.init(null); + return trans; + }, + _computeClipboardHash() { + const flavors = ["text/x-moz-url", "text/plain"]; + if ( + !Services.clipboard.hasDataMatchingFlavors( + flavors, + Ci.nsIClipboard.kGlobalClipboard + ) + ) { + return null; + } + const trans = this._createTransferable(); + flavors.forEach(trans.addDataFlavor); + try { + Services.clipboard.getData(trans, Ci.nsIClipboard.kGlobalClipboard); + const clipboardContent = {}; + trans.getAnyTransferData({}, clipboardContent); + const { data } = clipboardContent.value.QueryInterface( + Ci.nsISupportsString + ); + const bytes = new TextEncoder().encode(data); + const hasher = (this._hasher ||= Cc[ + "@mozilla.org/security/hash;1" + ].createInstance(Ci.nsICryptoHash)); + hasher.init(hasher.SHA256); + hasher.update(bytes, bytes.length); + return hasher.finish(true); + } catch (e) {} + return null; + }, + + init() { + this._log = console.createInstance({ + prefix: "ClipboardPrivacy", + }); + this._lastClipboardHash = this._computeClipboardHash(); + + // Here we track changes in active window / application, + // by filtering focus events and window closures. + const handleActivation = (win, activation) => { + if (activation) { + if (!this._globalActivation) { + // focus changed within this window, bail out. + return; + } + this._globalActivation = false; + } else if (!Services.focus.activeWindow) { + // focus is leaving this window: + // let's track whether it remains within the browser. + lazy.setTimeout(() => { + this._globalActivation = !Services.focus.activeWindow; + }, 100); + } + + const checkClipboardContent = () => { + const clipboardHash = this._computeClipboardHash(); + if (clipboardHash !== this._lastClipboardHash) { + this._isPrivateClipboard = + !activation && + (lazy.PrivateBrowsingUtils.permanentPrivateBrowsing || + lazy.PrivateBrowsingUtils.isWindowPrivate(win)); + this._lastClipboardHash = clipboardHash; + this._log.debug( + `Clipboard changed: private ${this._isPrivateClipboard}, hash ${clipboardHash}.` + ); + } + }; + + if (win.closed) { + checkClipboardContent(); + } else { + // defer clipboard access on DOM events to work-around tor-browser#42306 + lazy.setTimeout(checkClipboardContent, 0); + } + }; + const focusListener = e => + e.isTrusted && handleActivation(e.currentTarget, e.type === "focusin"); + const initWindow = win => { + for (const e of ["focusin", "focusout"]) { + win.addEventListener(e, focusListener); + } + }; + for (const w of Services.ww.getWindowEnumerator()) { + initWindow(w); + } + Services.ww.registerNotification((win, event) => { + switch (event) { + case "domwindowopened": + initWindow(win); + break; + case "domwindowclosed": + handleActivation(win, false); + if ( + this._isPrivateClipboard && + lazy.PrivateBrowsingUtils.isWindowPrivate(win) && + (this._shuttingDown || + !Array.from(Services.ww.getWindowEnumerator()).find( + w => + lazy.PrivateBrowsingUtils.isWindowPrivate(w) && + // We need to filter out the HIDDEN WebExtensions window, + // which might be private as well but is not UI-relevant. + !w.location.href.startsWith("chrome://extensions/") + )) + ) { + // no more private windows, empty private content if needed + this.emptyPrivate(); + } + } + }); + + lazy.AsyncShutdown.quitApplicationGranted.addBlocker( + "ClipboardPrivacy: removing private data", + () => { + this._shuttingDown = true; + this.emptyPrivate(); + } + ); + }, + emptyPrivate() { + if ( + this._isPrivateClipboard && + !Services.prefs.getBoolPref( + "browser.privatebrowsing.preserveClipboard", + false + ) && + this._lastClipboardHash === this._computeClipboardHash() + ) { + // nsIClipboard.emptyClipboard() does nothing in Wayland: + // we'll set an empty string as a work-around. + const trans = this._createTransferable(); + const flavor = "text/plain"; + trans.addDataFlavor(flavor); + const emptyString = Cc["@mozilla.org/supports-string;1"].createInstance( + Ci.nsISupportsString + ); + emptyString.data = ""; + trans.setTransferData(flavor, emptyString); + const { clipboard } = Services, + { kGlobalClipboard } = clipboard; + clipboard.setData(trans, null, kGlobalClipboard); + clipboard.emptyClipboard(kGlobalClipboard); + this._lastClipboardHash = null; + this._isPrivateClipboard = false; + this._log.info("Private clipboard emptied."); + } + }, +}; ===================================== browser/modules/moz.build ===================================== @@ -136,7 +136,6 @@ EXTRA_JS_MODULES += [ "PopupBlockerObserver.sys.mjs", "ProcessHangMonitor.sys.mjs", "Sanitizer.sys.mjs", - "SecurityLevelRestartNotification.sys.mjs", "SelectionChangedMenulist.sys.mjs", "SharingUtils.sys.mjs", "SiteDataManager.sys.mjs", @@ -149,6 +148,8 @@ EXTRA_JS_MODULES += [ MOZ_SRC_FILES += [ "ContextId.sys.mjs", + "ClipboardPrivacy.sys.mjs", + "SecurityLevelRestartNotification.sys.mjs", ] if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows": View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/b8… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/b8… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][base-browser-140.2.0esr-15.0-1] 3 commits: fixup! BB 42019: Empty browser's clipboard on browser shutdown
by Pier Angelo Vendrame (@pierov) 08 Sep '25

08 Sep '25
Pier Angelo Vendrame pushed to branch base-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser Commits: 24214f3e by Pier Angelo Vendrame at 2025-09-08T12:12:36+02:00 fixup! BB 42019: Empty browser's clipboard on browser shutdown BB 43770: Follow upstream's BrowserGlue simplifications. ClipboardPrivacy to its own file and initialize it from the manifest, rather than from BrowserGlue. - - - - - 92770da8 by Pier Angelo Vendrame at 2025-09-08T12:16:00+02:00 fixup! BB 40925: Implemented the Security Level component BB 43770: Follow upstream's BrowserGlue simplifications. Initialize the security level notification from the manifest. Also, since it was the only occurrence of the file path, move it to the moz-src:// scheme. - - - - - 88bb3bc2 by Pier Angelo Vendrame at 2025-09-08T12:25:21+02:00 fixup! BB 42027: Base Browser migration procedures. BB 43770: Follow upstream's BrowserGlue simplifications. - - - - - 5 changed files: - browser/components/BrowserComponents.manifest - browser/components/BrowserGlue.sys.mjs - browser/components/ProfileDataUpgrader.sys.mjs - + browser/modules/ClipboardPrivacy.sys.mjs - browser/modules/moz.build Changes: ===================================== browser/components/BrowserComponents.manifest ===================================== @@ -50,6 +50,8 @@ category browser-first-window-ready resource://gre/modules/CaptchaDetectionPingU category browser-first-window-ready resource://gre/modules/SandboxUtils.sys.mjs SandboxUtils.maybeWarnAboutMissingUserNamespaces #endif #endif +category browser-first-window-ready moz-src:///browser/modules/ClipboardPrivacy.sys.mjs ClipboardPrivacy.init +category browser-first-window-ready moz-src:///browser/modules/SecurityLevelRestartNotification.sys.mjs SecurityLevelRestartNotification.ready category browser-idle-startup resource:///modules/PlacesUIUtils.sys.mjs PlacesUIUtils.unblockToolbars category browser-idle-startup resource:///modules/BuiltInThemes.sys.mjs BuiltInThemes.ensureBuiltInThemes ===================================== browser/components/BrowserGlue.sys.mjs ===================================== @@ -12,7 +12,6 @@ ChromeUtils.defineESModuleGetters(lazy, { AWToolbarButton: "resource:///modules/aboutwelcome/AWToolbarUtils.sys.mjs", ASRouter: "resource:///modules/asrouter/ASRouter.sys.mjs", AddonManager: "resource://gre/modules/AddonManager.sys.mjs", - AsyncShutdown: "resource://gre/modules/AsyncShutdown.sys.mjs", BackupService: "resource:///modules/backup/BackupService.sys.mjs", BrowserSearchTelemetry: "moz-src:///browser/components/search/BrowserSearchTelemetry.sys.mjs", @@ -61,8 +60,6 @@ ChromeUtils.defineESModuleGetters(lazy, { ScreenshotsUtils: "resource:///modules/ScreenshotsUtils.sys.mjs", SearchSERPTelemetry: "moz-src:///browser/components/search/SearchSERPTelemetry.sys.mjs", - SecurityLevelRestartNotification: - "resource:///modules/SecurityLevelRestartNotification.sys.mjs", SessionStartup: "resource:///modules/sessionstore/SessionStartup.sys.mjs", SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs", ShortcutUtils: "resource://gre/modules/ShortcutUtils.sys.mjs", @@ -106,170 +103,6 @@ if (AppConstants.ENABLE_WEBDRIVER) { const PREF_PDFJS_ISDEFAULT_CACHE_STATE = "pdfjs.enabledCache.state"; -// Empty clipboard content from private windows on exit -// (tor-browser#42154) -const ClipboardPrivacy = { - _lastClipboardHash: null, - _globalActivation: false, - _isPrivateClipboard: false, - _hasher: null, - _shuttingDown: false, - _log: null, - - _createTransferable() { - const trans = Cc["@mozilla.org/widget/transferable;1"].createInstance( - Ci.nsITransferable - ); - trans.init(null); - return trans; - }, - _computeClipboardHash() { - const flavors = ["text/x-moz-url", "text/plain"]; - if ( - !Services.clipboard.hasDataMatchingFlavors( - flavors, - Ci.nsIClipboard.kGlobalClipboard - ) - ) { - return null; - } - const trans = this._createTransferable(); - flavors.forEach(trans.addDataFlavor); - try { - Services.clipboard.getData(trans, Ci.nsIClipboard.kGlobalClipboard); - const clipboardContent = {}; - trans.getAnyTransferData({}, clipboardContent); - const { data } = clipboardContent.value.QueryInterface( - Ci.nsISupportsString - ); - const bytes = new TextEncoder().encode(data); - const hasher = (this._hasher ||= Cc[ - "@mozilla.org/security/hash;1" - ].createInstance(Ci.nsICryptoHash)); - hasher.init(hasher.SHA256); - hasher.update(bytes, bytes.length); - return hasher.finish(true); - } catch (e) {} - return null; - }, - - startup() { - this._log = console.createInstance({ - prefix: "ClipboardPrivacy", - }); - this._lastClipboardHash = this._computeClipboardHash(); - - // Here we track changes in active window / application, - // by filtering focus events and window closures. - const handleActivation = (win, activation) => { - if (activation) { - if (!this._globalActivation) { - // focus changed within this window, bail out. - return; - } - this._globalActivation = false; - } else if (!Services.focus.activeWindow) { - // focus is leaving this window: - // let's track whether it remains within the browser. - lazy.setTimeout(() => { - this._globalActivation = !Services.focus.activeWindow; - }, 100); - } - - const checkClipboardContent = () => { - const clipboardHash = this._computeClipboardHash(); - if (clipboardHash !== this._lastClipboardHash) { - this._isPrivateClipboard = - !activation && - (lazy.PrivateBrowsingUtils.permanentPrivateBrowsing || - lazy.PrivateBrowsingUtils.isWindowPrivate(win)); - this._lastClipboardHash = clipboardHash; - this._log.debug( - `Clipboard changed: private ${this._isPrivateClipboard}, hash ${clipboardHash}.` - ); - } - }; - - if (win.closed) { - checkClipboardContent(); - } else { - // defer clipboard access on DOM events to work-around tor-browser#42306 - lazy.setTimeout(checkClipboardContent, 0); - } - }; - const focusListener = e => - e.isTrusted && handleActivation(e.currentTarget, e.type === "focusin"); - const initWindow = win => { - for (const e of ["focusin", "focusout"]) { - win.addEventListener(e, focusListener); - } - }; - for (const w of Services.ww.getWindowEnumerator()) { - initWindow(w); - } - Services.ww.registerNotification((win, event) => { - switch (event) { - case "domwindowopened": - initWindow(win); - break; - case "domwindowclosed": - handleActivation(win, false); - if ( - this._isPrivateClipboard && - lazy.PrivateBrowsingUtils.isWindowPrivate(win) && - (this._shuttingDown || - !Array.from(Services.ww.getWindowEnumerator()).find( - w => - lazy.PrivateBrowsingUtils.isWindowPrivate(w) && - // We need to filter out the HIDDEN WebExtensions window, - // which might be private as well but is not UI-relevant. - !w.location.href.startsWith("chrome://extensions/") - )) - ) { - // no more private windows, empty private content if needed - this.emptyPrivate(); - } - } - }); - - lazy.AsyncShutdown.quitApplicationGranted.addBlocker( - "ClipboardPrivacy: removing private data", - () => { - this._shuttingDown = true; - this.emptyPrivate(); - } - ); - }, - emptyPrivate() { - if ( - this._isPrivateClipboard && - !Services.prefs.getBoolPref( - "browser.privatebrowsing.preserveClipboard", - false - ) && - this._lastClipboardHash === this._computeClipboardHash() - ) { - // nsIClipboard.emptyClipboard() does nothing in Wayland: - // we'll set an empty string as a work-around. - const trans = this._createTransferable(); - const flavor = "text/plain"; - trans.addDataFlavor(flavor); - const emptyString = Cc["@mozilla.org/supports-string;1"].createInstance( - Ci.nsISupportsString - ); - emptyString.data = ""; - trans.setTransferData(flavor, emptyString); - const { clipboard } = Services, - { kGlobalClipboard } = clipboard; - clipboard.setData(trans, null, kGlobalClipboard); - clipboard.emptyClipboard(kGlobalClipboard); - this._lastClipboardHash = null; - this._isPrivateClipboard = false; - this._log.info("Private clipboard emptied."); - } - }, -}; - ChromeUtils.defineLazyGetter( lazy, "WeaveService", @@ -596,9 +429,7 @@ BrowserGlue.prototype = { // handle any UI migration this._migrateUI(); - - // Base Browser-specific version of _migrateUI. - this._migrateUIBB(); + lazy.ProfileDataUpgrader.upgradeBB(this._isNewProfile); if (!Services.prefs.prefHasUserValue(PREF_PDFJS_ISDEFAULT_CACHE_STATE)) { lazy.PdfJs.checkIsDefault(this._isNewProfile); @@ -984,10 +815,6 @@ BrowserGlue.prototype = { lazy.WeaveService.init(); } - lazy.SecurityLevelRestartNotification.ready(); - - ClipboardPrivacy.startup(); - lazy.BrowserUtils.callModulesFromCategory( { categoryName: "browser-first-window-ready", @@ -1823,83 +1650,6 @@ BrowserGlue.prototype = { } }, - _migrateUIBB() { - // Version 1: 13.0a3. Reset layout.css.prefers-color-scheme.content-override - // for tor-browser#41739. - // Version 2: 14.0a5: Reset the privacy tracking headers preferences since - // the UI is hidden. tor-browser#42777. - // Also, do not set - // dom.security.https_only_mode_send_http_background_request in - // the security level anymore (tor-browser#42149). - // Also, reset security.xfocsp.errorReporting.automatic since we - // hid its neterror checkbox. tor-browser#42653. - // Version 3: 14.0a7: Reset general.smoothScroll. tor-browser#42070. - // Version 4: 15.0a2: Drop ML components. tor-browser#44045. - const MIGRATION_VERSION = 4; - const MIGRATION_PREF = "basebrowser.migration.version"; - if (this._isNewProfile) { - // Do not migrate fresh profiles - Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); - return; - } else if (this._isNewProfile === undefined) { - // If this happens, check if upstream updated their function and do not - // set this member anymore! - console.error("_migrateUIBB: this._isNewProfile is undefined."); - } - // We do not care whether this is a new or old profile, since in version 1 - // we just quickly clear a user preference, which should not do anything to - // new profiles. - // Shall we ever raise the version number and have a watershed, we can add - // a check easily (any version > 0 will be an old profile). - const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0); - if (currentVersion < 1) { - Services.prefs.clearUserPref( - "layout.css.prefers-color-scheme.content-override" - ); - } - if (currentVersion < 2) { - for (const prefName of [ - "privacy.globalprivacycontrol.enabled", - "privacy.donottrackheader.enabled", - // Telemetry preference for if the user changed the value. - "privacy.globalprivacycontrol.was_ever_enabled", - // The next two preferences have no corresponding UI, but are related. - "privacy.globalprivacycontrol.functionality.enabled", - "privacy.globalprivacycontrol.pbmode.enabled", - "dom.security.https_only_mode_send_http_background_request", - "security.xfocsp.errorReporting.automatic", - ]) { - Services.prefs.clearUserPref(prefName); - } - } - if (currentVersion < 3) { - Services.prefs.clearUserPref("general.smoothScroll"); - } - if (currentVersion < 4) { - for (const prefName of [ - "browser.translations.enable", - "browser.ml.enable", - "browser.ml.chat.enabled", - "browser.ml.linkPreview.enabled", - "browser.tabs.groups.smart.enabled", - "browser.tabs.groups.smart.userEnabled", - "extensions.ml.enabled", - "pdfjs.enableAltText", - "pdfjs.enableAltTextForEnglish", - "pdfjs.enableGuessAltText", - "pdfjs.enableAltTextModelDownload", - "browser.urlbar.quicksuggest.mlEnabled", - "places.semanticHistory.featureGate", - ]) { - // Preferences are locked. Do not want user values to linger in the - // user's profile and become active if these preferences become unlocked - // in the future. - Services.prefs.clearUserPref(prefName); - } - } - Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); - }, - async _showUpgradeDialog() { const data = await lazy.OnboardingMessageProvider.getUpgradeMessage(); const { gBrowser } = lazy.BrowserWindowTracker.getTopWindow(); ===================================== browser/components/ProfileDataUpgrader.sys.mjs ===================================== @@ -900,4 +900,78 @@ export let ProfileDataUpgrader = { // Update the migration version. Services.prefs.setIntPref("browser.migration.version", newVersion); }, + + upgradeBB(isNewProfile) { + // Version 1: 13.0a3. Reset layout.css.prefers-color-scheme.content-override + // for tor-browser#41739. + // Version 2: 14.0a5: Reset the privacy tracking headers preferences since + // the UI is hidden. tor-browser#42777. + // Also, do not set + // dom.security.https_only_mode_send_http_background_request in + // the security level anymore (tor-browser#42149). + // Also, reset security.xfocsp.errorReporting.automatic since we + // hid its neterror checkbox. tor-browser#42653. + // Version 3: 14.0a7: Reset general.smoothScroll. tor-browser#42070. + // Version 4: 15.0a2: Drop ML components. tor-browser#44045. + const MIGRATION_VERSION = 4; + const MIGRATION_PREF = "basebrowser.migration.version"; + + if (isNewProfile) { + // Do not migrate fresh profiles + Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); + return; + } else if (isNewProfile === undefined) { + // If this happens, check if upstream updated their function and do not + // set this member anymore! + console.error("upgradeBB: isNewProfile is undefined."); + } + + const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0); + if (currentVersion < 1) { + Services.prefs.clearUserPref( + "layout.css.prefers-color-scheme.content-override" + ); + } + if (currentVersion < 2) { + for (const prefName of [ + "privacy.globalprivacycontrol.enabled", + "privacy.donottrackheader.enabled", + // Telemetry preference for if the user changed the value. + "privacy.globalprivacycontrol.was_ever_enabled", + // The next two preferences have no corresponding UI, but are related. + "privacy.globalprivacycontrol.functionality.enabled", + "privacy.globalprivacycontrol.pbmode.enabled", + "dom.security.https_only_mode_send_http_background_request", + "security.xfocsp.errorReporting.automatic", + ]) { + Services.prefs.clearUserPref(prefName); + } + } + if (currentVersion < 3) { + Services.prefs.clearUserPref("general.smoothScroll"); + } + if (currentVersion < 4) { + for (const prefName of [ + "browser.translations.enable", + "browser.ml.enable", + "browser.ml.chat.enabled", + "browser.ml.linkPreview.enabled", + "browser.tabs.groups.smart.enabled", + "browser.tabs.groups.smart.userEnabled", + "extensions.ml.enabled", + "pdfjs.enableAltText", + "pdfjs.enableAltTextForEnglish", + "pdfjs.enableGuessAltText", + "pdfjs.enableAltTextModelDownload", + "browser.urlbar.quicksuggest.mlEnabled", + "places.semanticHistory.featureGate", + ]) { + // Preferences are locked. Do not want user values to linger in the + // user's profile and become active if these preferences become unlocked + // in the future. + Services.prefs.clearUserPref(prefName); + } + } + Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); + }, }; ===================================== browser/modules/ClipboardPrivacy.sys.mjs ===================================== @@ -0,0 +1,178 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + AsyncShutdown: "resource://gre/modules/AsyncShutdown.sys.mjs", + PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", + setTimeout: "resource://gre/modules/Timer.sys.mjs", +}); + +/** + * Empty clipboard content from private windows on exit. + * + * See tor-browser#42154. + */ +export const ClipboardPrivacy = { + _lastClipboardHash: null, + _globalActivation: false, + _isPrivateClipboard: false, + _hasher: null, + _shuttingDown: false, + _log: null, + + _createTransferable() { + const trans = Cc["@mozilla.org/widget/transferable;1"].createInstance( + Ci.nsITransferable + ); + trans.init(null); + return trans; + }, + _computeClipboardHash() { + const flavors = ["text/x-moz-url", "text/plain"]; + if ( + !Services.clipboard.hasDataMatchingFlavors( + flavors, + Ci.nsIClipboard.kGlobalClipboard + ) + ) { + return null; + } + const trans = this._createTransferable(); + flavors.forEach(trans.addDataFlavor); + try { + Services.clipboard.getData(trans, Ci.nsIClipboard.kGlobalClipboard); + const clipboardContent = {}; + trans.getAnyTransferData({}, clipboardContent); + const { data } = clipboardContent.value.QueryInterface( + Ci.nsISupportsString + ); + const bytes = new TextEncoder().encode(data); + const hasher = (this._hasher ||= Cc[ + "@mozilla.org/security/hash;1" + ].createInstance(Ci.nsICryptoHash)); + hasher.init(hasher.SHA256); + hasher.update(bytes, bytes.length); + return hasher.finish(true); + } catch (e) {} + return null; + }, + + init() { + this._log = console.createInstance({ + prefix: "ClipboardPrivacy", + }); + this._lastClipboardHash = this._computeClipboardHash(); + + // Here we track changes in active window / application, + // by filtering focus events and window closures. + const handleActivation = (win, activation) => { + if (activation) { + if (!this._globalActivation) { + // focus changed within this window, bail out. + return; + } + this._globalActivation = false; + } else if (!Services.focus.activeWindow) { + // focus is leaving this window: + // let's track whether it remains within the browser. + lazy.setTimeout(() => { + this._globalActivation = !Services.focus.activeWindow; + }, 100); + } + + const checkClipboardContent = () => { + const clipboardHash = this._computeClipboardHash(); + if (clipboardHash !== this._lastClipboardHash) { + this._isPrivateClipboard = + !activation && + (lazy.PrivateBrowsingUtils.permanentPrivateBrowsing || + lazy.PrivateBrowsingUtils.isWindowPrivate(win)); + this._lastClipboardHash = clipboardHash; + this._log.debug( + `Clipboard changed: private ${this._isPrivateClipboard}, hash ${clipboardHash}.` + ); + } + }; + + if (win.closed) { + checkClipboardContent(); + } else { + // defer clipboard access on DOM events to work-around tor-browser#42306 + lazy.setTimeout(checkClipboardContent, 0); + } + }; + const focusListener = e => + e.isTrusted && handleActivation(e.currentTarget, e.type === "focusin"); + const initWindow = win => { + for (const e of ["focusin", "focusout"]) { + win.addEventListener(e, focusListener); + } + }; + for (const w of Services.ww.getWindowEnumerator()) { + initWindow(w); + } + Services.ww.registerNotification((win, event) => { + switch (event) { + case "domwindowopened": + initWindow(win); + break; + case "domwindowclosed": + handleActivation(win, false); + if ( + this._isPrivateClipboard && + lazy.PrivateBrowsingUtils.isWindowPrivate(win) && + (this._shuttingDown || + !Array.from(Services.ww.getWindowEnumerator()).find( + w => + lazy.PrivateBrowsingUtils.isWindowPrivate(w) && + // We need to filter out the HIDDEN WebExtensions window, + // which might be private as well but is not UI-relevant. + !w.location.href.startsWith("chrome://extensions/") + )) + ) { + // no more private windows, empty private content if needed + this.emptyPrivate(); + } + } + }); + + lazy.AsyncShutdown.quitApplicationGranted.addBlocker( + "ClipboardPrivacy: removing private data", + () => { + this._shuttingDown = true; + this.emptyPrivate(); + } + ); + }, + emptyPrivate() { + if ( + this._isPrivateClipboard && + !Services.prefs.getBoolPref( + "browser.privatebrowsing.preserveClipboard", + false + ) && + this._lastClipboardHash === this._computeClipboardHash() + ) { + // nsIClipboard.emptyClipboard() does nothing in Wayland: + // we'll set an empty string as a work-around. + const trans = this._createTransferable(); + const flavor = "text/plain"; + trans.addDataFlavor(flavor); + const emptyString = Cc["@mozilla.org/supports-string;1"].createInstance( + Ci.nsISupportsString + ); + emptyString.data = ""; + trans.setTransferData(flavor, emptyString); + const { clipboard } = Services, + { kGlobalClipboard } = clipboard; + clipboard.setData(trans, null, kGlobalClipboard); + clipboard.emptyClipboard(kGlobalClipboard); + this._lastClipboardHash = null; + this._isPrivateClipboard = false; + this._log.info("Private clipboard emptied."); + } + }, +}; ===================================== browser/modules/moz.build ===================================== @@ -136,7 +136,6 @@ EXTRA_JS_MODULES += [ "PopupBlockerObserver.sys.mjs", "ProcessHangMonitor.sys.mjs", "Sanitizer.sys.mjs", - "SecurityLevelRestartNotification.sys.mjs", "SelectionChangedMenulist.sys.mjs", "SharingUtils.sys.mjs", "SiteDataManager.sys.mjs", @@ -149,6 +148,8 @@ EXTRA_JS_MODULES += [ MOZ_SRC_FILES += [ "ContextId.sys.mjs", + "ClipboardPrivacy.sys.mjs", + "SecurityLevelRestartNotification.sys.mjs", ] if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows": View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/a1886d… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/a1886d… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][tor-browser-140.2.0esr-15.0-1] 9 commits: fixup! BB 42019: Empty browser's clipboard on browser shutdown
by Pier Angelo Vendrame (@pierov) 08 Sep '25

08 Sep '25
Pier Angelo Vendrame pushed to branch tor-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser Commits: d5582e87 by Pier Angelo Vendrame at 2025-09-08T12:03:34+02:00 fixup! BB 42019: Empty browser's clipboard on browser shutdown BB 43770: Follow upstream's BrowserGlue simplifications. ClipboardPrivacy to its own file and initialize it from the manifest, rather than from BrowserGlue. - - - - - d4c6e7a4 by Pier Angelo Vendrame at 2025-09-08T12:03:35+02:00 fixup! BB 40925: Implemented the Security Level component BB 43770: Follow upstream's BrowserGlue simplifications. Initialize the security level notification from the manifest. Also, since it was the only occurrence of the file path, move it to the moz-src:// scheme. - - - - - 8eccdc93 by Pier Angelo Vendrame at 2025-09-08T12:03:35+02:00 fixup! TB 40933: Add tor-launcher functionality BB 43770: Follow upstream's BrowserGlue simplifications. Moved the call to firstWindowLoaded to the manifest. - - - - - 167c0116 by Pier Angelo Vendrame at 2025-09-08T12:03:36+02:00 fixup! TB 8324: Prevent DNS proxy bypasses caused by Drag&Drop BB 43770: Follow upstream's BrowserGlue simplifications. - - - - - b45bb7f1 by Pier Angelo Vendrame at 2025-09-08T12:03:37+02:00 fixup! TB 43405: Show a prompt whenever we fail to apply Tor settings. BB 43770: Follow upstream's BrowserGlue simplifications. - - - - - ad267a06 by Pier Angelo Vendrame at 2025-09-08T12:03:37+02:00 fixup! TB 40458: Implement .tor.onion aliases Use proper private method and members. - - - - - a05bd724 by Pier Angelo Vendrame at 2025-09-08T12:03:38+02:00 fixup! TB 40458: Implement .tor.onion aliases BB 43770: Follow upstream's BrowserGlue simplifications. - - - - - a857af7e by Pier Angelo Vendrame at 2025-09-08T12:03:38+02:00 fixup! BB 42027: Base Browser migration procedures. BB 43770: Follow upstream's BrowserGlue simplifications. - - - - - 51ca3bdf by Pier Angelo Vendrame at 2025-09-08T12:03:39+02:00 fixup! TB 41435: Add a Tor Browser migration function BB 43770: Follow upstream's BrowserGlue simplifications. - - - - - 12 changed files: - browser/components/BrowserComponents.manifest - browser/components/BrowserGlue.sys.mjs - browser/components/ProfileDataUpgrader.sys.mjs - browser/components/onionservices/OnionAliasStore.sys.mjs - browser/components/onionservices/moz.build - browser/components/rulesets/RulesetsParent.sys.mjs - + browser/modules/ClipboardPrivacy.sys.mjs - browser/modules/moz.build - dom/base/ContentAreaDropListener.sys.mjs - toolkit/components/places/PlacesUtils.sys.mjs - toolkit/components/tor-launcher/tor-launcher.manifest - toolkit/modules/moz.build Changes: ===================================== browser/components/BrowserComponents.manifest ===================================== @@ -51,6 +51,11 @@ category browser-first-window-ready resource://gre/modules/CaptchaDetectionPingU category browser-first-window-ready resource://gre/modules/SandboxUtils.sys.mjs SandboxUtils.maybeWarnAboutMissingUserNamespaces #endif #endif +category browser-first-window-ready moz-src:///browser/modules/ClipboardPrivacy.sys.mjs ClipboardPrivacy.init +category browser-first-window-ready moz-src:///browser/modules/SecurityLevelRestartNotification.sys.mjs SecurityLevelRestartNotification.ready +category browser-first-window-ready moz-src:///toolkit/modules/DragDropFilter.sys.mjs DragDropFilter.init +category browser-first-window-ready moz-src:///browser/modules/TorSettingsNotification.sys.mjs TorSettingsNotification.ready +category browser-first-window-ready moz-src:///browser/components/onionservices/OnionAliasStore.sys.mjs OnionAliasStore.init category browser-idle-startup resource:///modules/PlacesUIUtils.sys.mjs PlacesUIUtils.unblockToolbars category browser-idle-startup resource:///modules/BuiltInThemes.sys.mjs BuiltInThemes.ensureBuiltInThemes @@ -94,5 +99,6 @@ category browser-quit-application-granted moz-src:///browser/components/search/S category browser-quit-application-granted resource://gre/modules/UpdateListener.sys.mjs UpdateListener.reset #endif category browser-quit-application-granted resource:///modules/UrlbarSearchTermsPersistence.sys.mjs UrlbarSearchTermsPersistence.uninit +category browser-quit-application-granted moz-src:///browser/components/onionservices/OnionAliasStore.sys.mjs OnionAliasStore.uninit category search-service-notification moz-src:///browser/components/search/SearchUIUtils.sys.mjs SearchUIUtils.showSearchServiceNotification ===================================== browser/components/BrowserGlue.sys.mjs ===================================== @@ -12,7 +12,6 @@ ChromeUtils.defineESModuleGetters(lazy, { AWToolbarButton: "resource:///modules/aboutwelcome/AWToolbarUtils.sys.mjs", ASRouter: "resource:///modules/asrouter/ASRouter.sys.mjs", AddonManager: "resource://gre/modules/AddonManager.sys.mjs", - AsyncShutdown: "resource://gre/modules/AsyncShutdown.sys.mjs", BackupService: "resource:///modules/backup/BackupService.sys.mjs", BrowserSearchTelemetry: "moz-src:///browser/components/search/BrowserSearchTelemetry.sys.mjs", @@ -31,7 +30,6 @@ ChromeUtils.defineESModuleGetters(lazy, { DistributionManagement: "resource:///modules/distribution.sys.mjs", DownloadsViewableInternally: "resource:///modules/DownloadsViewableInternally.sys.mjs", - DragDropFilter: "resource://gre/modules/DragDropFilter.sys.mjs", ExtensionsUI: "resource:///modules/ExtensionsUI.sys.mjs", // FilePickerCrashed is used by the `listeners` object below. // eslint-disable-next-line mozilla/valid-lazy @@ -42,7 +40,6 @@ ChromeUtils.defineESModuleGetters(lazy, { LoginHelper: "resource://gre/modules/LoginHelper.sys.mjs", MigrationUtils: "resource:///modules/MigrationUtils.sys.mjs", NimbusFeatures: "resource://nimbus/ExperimentAPI.sys.mjs", - OnionAliasStore: "resource:///modules/OnionAliasStore.sys.mjs", OnboardingMessageProvider: "resource:///modules/asrouter/OnboardingMessageProvider.sys.mjs", PageDataService: "resource:///modules/pagedata/PageDataService.sys.mjs", @@ -63,8 +60,6 @@ ChromeUtils.defineESModuleGetters(lazy, { ScreenshotsUtils: "resource:///modules/ScreenshotsUtils.sys.mjs", SearchSERPTelemetry: "moz-src:///browser/components/search/SearchSERPTelemetry.sys.mjs", - SecurityLevelRestartNotification: - "resource:///modules/SecurityLevelRestartNotification.sys.mjs", SessionStartup: "resource:///modules/sessionstore/SessionStartup.sys.mjs", SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs", ShortcutUtils: "resource://gre/modules/ShortcutUtils.sys.mjs", @@ -75,11 +70,6 @@ ChromeUtils.defineESModuleGetters(lazy, { TelemetryReportingPolicy: "resource://gre/modules/TelemetryReportingPolicy.sys.mjs", TRRRacer: "resource:///modules/TRRPerformance.sys.mjs", - TorConnect: "resource://gre/modules/TorConnect.sys.mjs", - TorConnectTopics: "resource://gre/modules/TorConnect.sys.mjs", - TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs", - TorSettingsNotification: - "resource:///modules/TorSettingsNotification.sys.mjs", WebChannel: "resource://gre/modules/WebChannel.sys.mjs", WebProtocolHandlerRegistrar: "resource:///modules/WebProtocolHandlerRegistrar.sys.mjs", @@ -113,170 +103,6 @@ if (AppConstants.ENABLE_WEBDRIVER) { const PREF_PDFJS_ISDEFAULT_CACHE_STATE = "pdfjs.enabledCache.state"; -// Empty clipboard content from private windows on exit -// (tor-browser#42154) -const ClipboardPrivacy = { - _lastClipboardHash: null, - _globalActivation: false, - _isPrivateClipboard: false, - _hasher: null, - _shuttingDown: false, - _log: null, - - _createTransferable() { - const trans = Cc["@mozilla.org/widget/transferable;1"].createInstance( - Ci.nsITransferable - ); - trans.init(null); - return trans; - }, - _computeClipboardHash() { - const flavors = ["text/x-moz-url", "text/plain"]; - if ( - !Services.clipboard.hasDataMatchingFlavors( - flavors, - Ci.nsIClipboard.kGlobalClipboard - ) - ) { - return null; - } - const trans = this._createTransferable(); - flavors.forEach(trans.addDataFlavor); - try { - Services.clipboard.getData(trans, Ci.nsIClipboard.kGlobalClipboard); - const clipboardContent = {}; - trans.getAnyTransferData({}, clipboardContent); - const { data } = clipboardContent.value.QueryInterface( - Ci.nsISupportsString - ); - const bytes = new TextEncoder().encode(data); - const hasher = (this._hasher ||= Cc[ - "@mozilla.org/security/hash;1" - ].createInstance(Ci.nsICryptoHash)); - hasher.init(hasher.SHA256); - hasher.update(bytes, bytes.length); - return hasher.finish(true); - } catch (e) {} - return null; - }, - - startup() { - this._log = console.createInstance({ - prefix: "ClipboardPrivacy", - }); - this._lastClipboardHash = this._computeClipboardHash(); - - // Here we track changes in active window / application, - // by filtering focus events and window closures. - const handleActivation = (win, activation) => { - if (activation) { - if (!this._globalActivation) { - // focus changed within this window, bail out. - return; - } - this._globalActivation = false; - } else if (!Services.focus.activeWindow) { - // focus is leaving this window: - // let's track whether it remains within the browser. - lazy.setTimeout(() => { - this._globalActivation = !Services.focus.activeWindow; - }, 100); - } - - const checkClipboardContent = () => { - const clipboardHash = this._computeClipboardHash(); - if (clipboardHash !== this._lastClipboardHash) { - this._isPrivateClipboard = - !activation && - (lazy.PrivateBrowsingUtils.permanentPrivateBrowsing || - lazy.PrivateBrowsingUtils.isWindowPrivate(win)); - this._lastClipboardHash = clipboardHash; - this._log.debug( - `Clipboard changed: private ${this._isPrivateClipboard}, hash ${clipboardHash}.` - ); - } - }; - - if (win.closed) { - checkClipboardContent(); - } else { - // defer clipboard access on DOM events to work-around tor-browser#42306 - lazy.setTimeout(checkClipboardContent, 0); - } - }; - const focusListener = e => - e.isTrusted && handleActivation(e.currentTarget, e.type === "focusin"); - const initWindow = win => { - for (const e of ["focusin", "focusout"]) { - win.addEventListener(e, focusListener); - } - }; - for (const w of Services.ww.getWindowEnumerator()) { - initWindow(w); - } - Services.ww.registerNotification((win, event) => { - switch (event) { - case "domwindowopened": - initWindow(win); - break; - case "domwindowclosed": - handleActivation(win, false); - if ( - this._isPrivateClipboard && - lazy.PrivateBrowsingUtils.isWindowPrivate(win) && - (this._shuttingDown || - !Array.from(Services.ww.getWindowEnumerator()).find( - w => - lazy.PrivateBrowsingUtils.isWindowPrivate(w) && - // We need to filter out the HIDDEN WebExtensions window, - // which might be private as well but is not UI-relevant. - !w.location.href.startsWith("chrome://extensions/") - )) - ) { - // no more private windows, empty private content if needed - this.emptyPrivate(); - } - } - }); - - lazy.AsyncShutdown.quitApplicationGranted.addBlocker( - "ClipboardPrivacy: removing private data", - () => { - this._shuttingDown = true; - this.emptyPrivate(); - } - ); - }, - emptyPrivate() { - if ( - this._isPrivateClipboard && - !Services.prefs.getBoolPref( - "browser.privatebrowsing.preserveClipboard", - false - ) && - this._lastClipboardHash === this._computeClipboardHash() - ) { - // nsIClipboard.emptyClipboard() does nothing in Wayland: - // we'll set an empty string as a work-around. - const trans = this._createTransferable(); - const flavor = "text/plain"; - trans.addDataFlavor(flavor); - const emptyString = Cc["@mozilla.org/supports-string;1"].createInstance( - Ci.nsISupportsString - ); - emptyString.data = ""; - trans.setTransferData(flavor, emptyString); - const { clipboard } = Services, - { kGlobalClipboard } = clipboard; - clipboard.setData(trans, null, kGlobalClipboard); - clipboard.emptyClipboard(kGlobalClipboard); - this._lastClipboardHash = null; - this._isPrivateClipboard = false; - this._log.info("Private clipboard emptied."); - } - }, -}; - ChromeUtils.defineLazyGetter( lazy, "WeaveService", @@ -603,13 +429,8 @@ BrowserGlue.prototype = { // handle any UI migration this._migrateUI(); - - // Base Browser-specific version of _migrateUI. - this._migrateUIBB(); - - // Handle any TBB-specific migration before showing the UI. Keep after - // _migrateUI to make sure this._isNewProfile has been defined. - this._migrateUITBB(); + lazy.ProfileDataUpgrader.upgradeBB(this._isNewProfile); + lazy.ProfileDataUpgrader.upgradeTB(this._isNewProfile); if (!Services.prefs.prefHasUserValue(PREF_PDFJS_ISDEFAULT_CACHE_STATE)) { lazy.PdfJs.checkIsDefault(this._isNewProfile); @@ -995,16 +816,6 @@ BrowserGlue.prototype = { lazy.WeaveService.init(); } - lazy.SecurityLevelRestartNotification.ready(); - - lazy.DragDropFilter.init(); - - lazy.TorProviderBuilder.firstWindowLoaded(); - - lazy.TorSettingsNotification.ready(); - - ClipboardPrivacy.startup(); - lazy.BrowserUtils.callModulesFromCategory( { categoryName: "browser-first-window-ready", @@ -1104,7 +915,6 @@ BrowserGlue.prototype = { // can perform at-shutdown tasks later in shutdown. Services.fog; }, - () => lazy.OnionAliasStore.uninit(), ]; for (let task of tasks) { @@ -1375,30 +1185,6 @@ BrowserGlue.prototype = { }, }, - { - task: () => { - if (!lazy.TorConnect.shouldShowTorConnect) { - // we will take this path when the user is using the legacy tor launcher or - // when Tor Browser didn't launch its own tor. - lazy.OnionAliasStore.init(); - } else { - // this path is taken when using about:torconnect, we wait to init - // after we are bootstrapped and connected to tor - const topic = lazy.TorConnectTopics.BootstrapComplete; - let bootstrapObserver = { - observe(aSubject, aTopic) { - if (aTopic === topic) { - lazy.OnionAliasStore.init(); - // we only need to init once, so remove ourselves as an obvserver - Services.obs.removeObserver(this, topic); - } - }, - }; - Services.obs.addObserver(bootstrapObserver, topic); - } - }, - }, - // Run TRR performance measurements for DoH. { name: "doh-rollout.trrRacer.run", @@ -1865,208 +1651,6 @@ BrowserGlue.prototype = { } }, - _migrateUIBB() { - // Version 1: 13.0a3. Reset layout.css.prefers-color-scheme.content-override - // for tor-browser#41739. - // Version 2: 14.0a5: Reset the privacy tracking headers preferences since - // the UI is hidden. tor-browser#42777. - // Also, do not set - // dom.security.https_only_mode_send_http_background_request in - // the security level anymore (tor-browser#42149). - // Also, reset security.xfocsp.errorReporting.automatic since we - // hid its neterror checkbox. tor-browser#42653. - // Version 3: 14.0a7: Reset general.smoothScroll. tor-browser#42070. - // Version 4: 15.0a2: Drop ML components. tor-browser#44045. - const MIGRATION_VERSION = 4; - const MIGRATION_PREF = "basebrowser.migration.version"; - if (this._isNewProfile) { - // Do not migrate fresh profiles - Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); - return; - } else if (this._isNewProfile === undefined) { - // If this happens, check if upstream updated their function and do not - // set this member anymore! - console.error("_migrateUIBB: this._isNewProfile is undefined."); - } - // We do not care whether this is a new or old profile, since in version 1 - // we just quickly clear a user preference, which should not do anything to - // new profiles. - // Shall we ever raise the version number and have a watershed, we can add - // a check easily (any version > 0 will be an old profile). - const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0); - if (currentVersion < 1) { - Services.prefs.clearUserPref( - "layout.css.prefers-color-scheme.content-override" - ); - } - if (currentVersion < 2) { - for (const prefName of [ - "privacy.globalprivacycontrol.enabled", - "privacy.donottrackheader.enabled", - // Telemetry preference for if the user changed the value. - "privacy.globalprivacycontrol.was_ever_enabled", - // The next two preferences have no corresponding UI, but are related. - "privacy.globalprivacycontrol.functionality.enabled", - "privacy.globalprivacycontrol.pbmode.enabled", - "dom.security.https_only_mode_send_http_background_request", - "security.xfocsp.errorReporting.automatic", - ]) { - Services.prefs.clearUserPref(prefName); - } - } - if (currentVersion < 3) { - Services.prefs.clearUserPref("general.smoothScroll"); - } - if (currentVersion < 4) { - for (const prefName of [ - "browser.translations.enable", - "browser.ml.enable", - "browser.ml.chat.enabled", - "browser.ml.linkPreview.enabled", - "browser.tabs.groups.smart.enabled", - "browser.tabs.groups.smart.userEnabled", - "extensions.ml.enabled", - "pdfjs.enableAltText", - "pdfjs.enableAltTextForEnglish", - "pdfjs.enableGuessAltText", - "pdfjs.enableAltTextModelDownload", - "browser.urlbar.quicksuggest.mlEnabled", - "places.semanticHistory.featureGate", - ]) { - // Preferences are locked. Do not want user values to linger in the - // user's profile and become active if these preferences become unlocked - // in the future. - Services.prefs.clearUserPref(prefName); - } - } - Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); - }, - - // Use this method for any TBB migration that can be run just before showing - // the UI. - // Anything that critically needs to be migrated earlier should not use this. - async _migrateUITBB() { - // Version 1: Tor Browser 12.0. We use it to remove langpacks, after the - // migration to packaged locales. - // Version 2: Tor Browser 13.0/13.0a1: tor-browser#41845. Also, removed some - // torbutton preferences that are not used anymore. - // Version 3: Tor Browser 13.0.7/13.5a3: Remove blockchair - // (tor-browser#42283). - // Version 4: Tor Browser 14.0a4 (2024-09-02): Remove Twitter, Yahoo and - // YouTube search engines (tor-browser#41835). - // Version 5: Tor Browser 14.0a5: Clear user preference for CFR settings - // since we hid the UI (tor-browser#43118). - // Version 6: Tor Browser 14.5a3: Clear preference for TorSettings that is - // no longer used (tor-browser#41921). - // Drop unused TorConnect setting (tor-browser#43462). - // Version 7: Tor Browser 14.5a6: Clear home page update url preference - // (tor-browser#43567). - // Version 8: Tor Browser 15.0a2: Remove legacy search addons - // (tor-browser#43111). - const TBB_MIGRATION_VERSION = 8; - const MIGRATION_PREF = "torbrowser.migration.version"; - - // If we decide to force updating users to pass through any version - // following 12.0, we can remove this check, and check only whether - // MIGRATION_PREF has a user value, like Mozilla does. - if (this._isNewProfile) { - // Do not migrate fresh profiles - Services.prefs.setIntPref(MIGRATION_PREF, TBB_MIGRATION_VERSION); - return; - } else if (this._isNewProfile === undefined) { - // If this happens, check if upstream updated their function and do not - // set this member anymore! - console.error("_migrateUITBB: this._isNewProfile is undefined."); - } - - const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0); - const removeLangpacks = async () => { - for (const addon of await AddonManager.getAddonsByTypes(["locale"])) { - await addon.uninstall(); - } - }; - if (currentVersion < 1) { - try { - await removeLangpacks(); - } catch (err) { - console.error("Could not remove langpacks", err); - } - } - if (currentVersion < 2) { - const prefToClear = [ - // tor-browser#41845: We were forcing these value by check the value of - // automatic PBM. We decided not to change - "browser.cache.disk.enable", - "places.history.enabled", - "security.nocertdb", - "permissions.memory_only", - // Old torbutton preferences not used anymore. - "extensions.torbutton.loglevel", - "extensions.torbutton.logmethod", - "extensions.torbutton.pref_fixup_version", - "extensions.torbutton.resize_new_windows", - "extensions.torbutton.startup", - "extensions.torlauncher.prompt_for_locale", - "extensions.torlauncher.loglevel", - "extensions.torlauncher.logmethod", - "extensions.torlauncher.torrc_fixup_version", - ]; - for (const pref of prefToClear) { - if (Services.prefs.prefHasUserValue(pref)) { - Services.prefs.clearUserPref(pref); - } - } - } - const dropAddons = async list => { - for (const id of list) { - try { - const engine = await lazy.AddonManager.getAddonByID(id); - await engine?.uninstall(); - } catch {} - } - }; - if (currentVersion < 3) { - await dropAddons([ - "blockchair(a)search.mozilla.org", - "blockchair-onion(a)search.mozilla.org", - ]); - } - if (currentVersion < 4) { - await dropAddons([ - "twitter(a)search.mozilla.org", - "yahoo(a)search.mozilla.org", - "youtube(a)search.mozilla.org", - ]); - } - if (currentVersion < 5) { - for (const pref of [ - "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons", - "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features", - ]) { - Services.prefs.clearUserPref(pref); - } - } - if (currentVersion < 6) { - Services.prefs.clearUserPref("torbrowser.settings.enabled"); - Services.prefs.clearUserPref("torbrowser.bootstrap.allow_internet_test"); - } - if (currentVersion < 7) { - Services.prefs.clearUserPref("torbrowser.post_update.url"); - } - if (currentVersion < 8) { - await dropAddons([ - "ddg(a)search.mozilla.org", - "ddg-onion(a)search.mozilla.org", - "google(a)search.mozilla.org", - "startpage(a)search.mozilla.org", - "startpage-onion(a)search.mozilla.org", - "wikipedia(a)search.mozilla.org", - ]); - } - - Services.prefs.setIntPref(MIGRATION_PREF, TBB_MIGRATION_VERSION); - }, - async _showUpgradeDialog() { const data = await lazy.OnboardingMessageProvider.getUpgradeMessage(); const { gBrowser } = lazy.BrowserWindowTracker.getTopWindow(); ===================================== browser/components/ProfileDataUpgrader.sys.mjs ===================================== @@ -900,4 +900,200 @@ export let ProfileDataUpgrader = { // Update the migration version. Services.prefs.setIntPref("browser.migration.version", newVersion); }, + + upgradeBB(isNewProfile) { + // Version 1: 13.0a3. Reset layout.css.prefers-color-scheme.content-override + // for tor-browser#41739. + // Version 2: 14.0a5: Reset the privacy tracking headers preferences since + // the UI is hidden. tor-browser#42777. + // Also, do not set + // dom.security.https_only_mode_send_http_background_request in + // the security level anymore (tor-browser#42149). + // Also, reset security.xfocsp.errorReporting.automatic since we + // hid its neterror checkbox. tor-browser#42653. + // Version 3: 14.0a7: Reset general.smoothScroll. tor-browser#42070. + // Version 4: 15.0a2: Drop ML components. tor-browser#44045. + const MIGRATION_VERSION = 4; + const MIGRATION_PREF = "basebrowser.migration.version"; + + if (isNewProfile) { + // Do not migrate fresh profiles + Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); + return; + } else if (isNewProfile === undefined) { + // If this happens, check if upstream updated their function and do not + // set this member anymore! + console.error("upgradeBB: isNewProfile is undefined."); + } + + const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0); + if (currentVersion < 1) { + Services.prefs.clearUserPref( + "layout.css.prefers-color-scheme.content-override" + ); + } + if (currentVersion < 2) { + for (const prefName of [ + "privacy.globalprivacycontrol.enabled", + "privacy.donottrackheader.enabled", + // Telemetry preference for if the user changed the value. + "privacy.globalprivacycontrol.was_ever_enabled", + // The next two preferences have no corresponding UI, but are related. + "privacy.globalprivacycontrol.functionality.enabled", + "privacy.globalprivacycontrol.pbmode.enabled", + "dom.security.https_only_mode_send_http_background_request", + "security.xfocsp.errorReporting.automatic", + ]) { + Services.prefs.clearUserPref(prefName); + } + } + if (currentVersion < 3) { + Services.prefs.clearUserPref("general.smoothScroll"); + } + if (currentVersion < 4) { + for (const prefName of [ + "browser.translations.enable", + "browser.ml.enable", + "browser.ml.chat.enabled", + "browser.ml.linkPreview.enabled", + "browser.tabs.groups.smart.enabled", + "browser.tabs.groups.smart.userEnabled", + "extensions.ml.enabled", + "pdfjs.enableAltText", + "pdfjs.enableAltTextForEnglish", + "pdfjs.enableGuessAltText", + "pdfjs.enableAltTextModelDownload", + "browser.urlbar.quicksuggest.mlEnabled", + "places.semanticHistory.featureGate", + ]) { + // Preferences are locked. Do not want user values to linger in the + // user's profile and become active if these preferences become unlocked + // in the future. + Services.prefs.clearUserPref(prefName); + } + } + Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); + }, + + async upgradeTB(isNewProfile) { + // Version 1: Tor Browser 12.0. We use it to remove langpacks, after the + // migration to packaged locales. + // Version 2: Tor Browser 13.0/13.0a1: tor-browser#41845. Also, removed some + // torbutton preferences that are not used anymore. + // Version 3: Tor Browser 13.0.7/13.5a3: Remove blockchair + // (tor-browser#42283). + // Version 4: Tor Browser 14.0a4 (2024-09-02): Remove Twitter, Yahoo and + // YouTube search engines (tor-browser#41835). + // Version 5: Tor Browser 14.0a5: Clear user preference for CFR settings + // since we hid the UI (tor-browser#43118). + // Version 6: Tor Browser 14.5a3: Clear preference for TorSettings that is + // no longer used (tor-browser#41921). + // Drop unused TorConnect setting (tor-browser#43462). + // Version 7: Tor Browser 14.5a6: Clear home page update url preference + // (tor-browser#43567). + // Version 8: Tor Browser 15.0a2: Remove legacy search addons + // (tor-browser#43111). + const TBB_MIGRATION_VERSION = 8; + const MIGRATION_PREF = "torbrowser.migration.version"; + + // If we decide to force updating users to pass through any version + // following 12.0, we can remove this check, and check only whether + // MIGRATION_PREF has a user value, like Mozilla does. + if (isNewProfile) { + // Do not migrate fresh profiles + Services.prefs.setIntPref(MIGRATION_PREF, TBB_MIGRATION_VERSION); + return; + } else if (isNewProfile === undefined) { + // If this happens, check if upstream updated their function and do not + // set this member anymore! + console.error("upgradeTB: isNewProfile is undefined."); + } + + const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0); + const removeLangpacks = async () => { + for (const addon of await AddonManager.getAddonsByTypes(["locale"])) { + await addon.uninstall(); + } + }; + if (currentVersion < 1) { + try { + await removeLangpacks(); + } catch (err) { + console.error("Could not remove langpacks", err); + } + } + if (currentVersion < 2) { + const prefToClear = [ + // tor-browser#41845: We were forcing these value by check the value of + // automatic PBM. We decided not to change + "browser.cache.disk.enable", + "places.history.enabled", + "security.nocertdb", + "permissions.memory_only", + // Old torbutton preferences not used anymore. + "extensions.torbutton.loglevel", + "extensions.torbutton.logmethod", + "extensions.torbutton.pref_fixup_version", + "extensions.torbutton.resize_new_windows", + "extensions.torbutton.startup", + "extensions.torlauncher.prompt_for_locale", + "extensions.torlauncher.loglevel", + "extensions.torlauncher.logmethod", + "extensions.torlauncher.torrc_fixup_version", + ]; + for (const pref of prefToClear) { + if (Services.prefs.prefHasUserValue(pref)) { + Services.prefs.clearUserPref(pref); + } + } + } + const dropAddons = async list => { + for (const id of list) { + try { + const engine = await lazy.AddonManager.getAddonByID(id); + await engine?.uninstall(); + } catch {} + } + }; + if (currentVersion < 3) { + await dropAddons([ + "blockchair(a)search.mozilla.org", + "blockchair-onion(a)search.mozilla.org", + ]); + } + if (currentVersion < 4) { + await dropAddons([ + "twitter(a)search.mozilla.org", + "yahoo(a)search.mozilla.org", + "youtube(a)search.mozilla.org", + ]); + } + if (currentVersion < 5) { + for (const pref of [ + "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons", + "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features", + ]) { + Services.prefs.clearUserPref(pref); + } + } + if (currentVersion < 6) { + Services.prefs.clearUserPref("torbrowser.settings.enabled"); + Services.prefs.clearUserPref("torbrowser.bootstrap.allow_internet_test"); + } + if (currentVersion < 7) { + Services.prefs.clearUserPref("torbrowser.post_update.url"); + } + if (currentVersion < 8) { + await dropAddons([ + "ddg(a)search.mozilla.org", + "ddg-onion(a)search.mozilla.org", + "google(a)search.mozilla.org", + "startpage(a)search.mozilla.org", + "startpage-onion(a)search.mozilla.org", + "wikipedia(a)search.mozilla.org", + ]); + } + + Services.prefs.setIntPref(MIGRATION_PREF, TBB_MIGRATION_VERSION); + }, }; ===================================== browser/components/onionservices/OnionAliasStore.sys.mjs ===================================== @@ -1,4 +1,6 @@ -// Copyright (c) 2022, The Tor Project, Inc. +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import { setTimeout, clearTimeout } from "resource://gre/modules/Timer.sys.mjs"; @@ -6,7 +8,10 @@ const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { JSONFile: "resource://gre/modules/JSONFile.sys.mjs", - TorRequestWatch: "resource:///modules/TorRequestWatch.sys.mjs", + TorConnect: "resource://gre/modules/TorConnect.sys.mjs", + TorConnectTopics: "resource://gre/modules/TorConnect.sys.mjs", + TorRequestWatch: + "moz-src:///browser/components/onionservices/TorRequestWatch.sys.mjs", }); /* OnionAliasStore observer topics */ @@ -84,12 +89,14 @@ class Channel { }; } + #enabled; + constructor(name, pathPrefix, jwk, scope, enabled) { this.name = name; this.pathPrefix = pathPrefix; this.jwk = jwk; this.scope = scope; - this._enabled = enabled; + this.#enabled = enabled; this.mappings = []; this.currentTimestamp = 0; @@ -158,10 +165,10 @@ class Channel { log.debug( `Downloaded and verified rules for ${this.name}, now uncompressing` ); - this._makeMappings(JSON.parse(await gunzip(rulesGz))); + this.#makeMappings(JSON.parse(await gunzip(rulesGz))); } - _makeMappings(rules) { + #makeMappings(rules) { const toTest = /^https?:\/\/[a-zA-Z0-9\.]{56}\.onion$/; const mappings = []; rules.rulesets.forEach(rule => { @@ -210,7 +217,7 @@ class Channel { async updateMappings(force) { force = force === undefined ? false : !!force; - if (!this._enabled && !force) { + if (!this.#enabled && !force) { return; } await this.updateLatestTimestamp(); @@ -224,10 +231,10 @@ class Channel { } get enabled() { - return this._enabled; + return this.#enabled; } set enabled(enabled) { - this._enabled = enabled; + this.#enabled = enabled; if (!enabled) { this.mappings = []; this.currentTimestamp = 0; @@ -243,7 +250,7 @@ class Channel { pathPrefix: this.pathPrefix, jwk: this.jwk, scope, - enabled: this._enabled, + enabled: this.#enabled, mappings: this.mappings, currentTimestamp: this.currentTimestamp, }; @@ -277,37 +284,40 @@ class _OnionAliasStore { return 86400 * 1000; // 1 day, like HTTPS-Everywhere } - constructor() { - this._channels = new Map(); - this._rulesetTimeout = null; - this._lastCheck = 0; - this._storage = null; - } + #channels = new Map(); + #rulesetTimeout = null; + #lastCheck = 0; + #storage = null; async init() { lazy.TorRequestWatch.start(); - await this._loadSettings(); - if (this.enabled) { - await this._startUpdates(); + await this.#loadSettings(); + if (this.enabled && !lazy.TorConnect.shouldShowTorConnect) { + await this.#startUpdates(); + } else { + Services.obs.addObserver(this, lazy.TorConnectTopics.BootstrapComplete); } Services.prefs.addObserver(kPrefOnionAliasEnabled, this); } uninit() { - this._clear(); - if (this._rulesetTimeout) { - clearTimeout(this._rulesetTimeout); + this.#clear(); + if (this.#rulesetTimeout) { + clearTimeout(this.#rulesetTimeout); } - this._rulesetTimeout = null; + this.#rulesetTimeout = null; + + Services.obs.removeObserver(this, lazy.TorConnectTopics.BootstrapComplete); Services.prefs.removeObserver(kPrefOnionAliasEnabled, this); + lazy.TorRequestWatch.stop(); } async getChannels() { - if (this._storage === null) { - await this._loadSettings(); + if (this.#storage === null) { + await this.#loadSettings(); } - return Array.from(this._channels.values(), ch => ch.toJSON()); + return Array.from(this.#channels.values(), ch => ch.toJSON()); } async setChannel(chanData) { @@ -328,20 +338,20 @@ class _OnionAliasStore { ); // Call makeKey to make it throw if the key is invalid await ch.makeKey(); - this._channels.set(name, ch); - this._applyMappings(); - this._saveSettings(); - setTimeout(this._notifyChanges.bind(this), 1); + this.#channels.set(name, ch); + this.#applyMappings(); + this.#saveSettings(); + setTimeout(this.#notifyChanges.bind(this), 1); return ch; } enableChannel(name, enabled) { - const channel = this._channels.get(name); + const channel = this.#channels.get(name); if (channel !== null) { channel.enabled = enabled; - this._applyMappings(); - this._saveSettings(); - this._notifyChanges(); + this.#applyMappings(); + this.#saveSettings(); + this.#notifyChanges(); if (this.enabled && enabled && !channel.currentTimestamp) { this.updateChannel(name); } @@ -352,46 +362,46 @@ class _OnionAliasStore { if (!this.enabled) { throw Error("Onion Aliases are disabled"); } - const channel = this._channels.get(name); + const channel = this.#channels.get(name); if (channel === null) { throw Error("Channel not found"); } await channel.updateMappings(true); - this._saveSettings(); - this._applyMappings(); - setTimeout(this._notifyChanges.bind(this), 1); + this.#saveSettings(); + this.#applyMappings(); + setTimeout(this.#notifyChanges.bind(this), 1); return channel; } deleteChannel(name) { - if (this._channels.delete(name)) { - this._saveSettings(); - this._applyMappings(); - this._notifyChanges(); + if (this.#channels.delete(name)) { + this.#saveSettings(); + this.#applyMappings(); + this.#notifyChanges(); } } - async _loadSettings() { - if (this._storage !== null) { + async #loadSettings() { + if (this.#storage !== null) { return; } - this._channels = new Map(); - this._storage = new lazy.JSONFile({ + this.#channels = new Map(); + this.#storage = new lazy.JSONFile({ path: PathUtils.join( Services.dirsvc.get("ProfD", Ci.nsIFile).path, "onion-aliases.json" ), - dataPostProcessor: this._settingsProcessor.bind(this), + dataPostProcessor: this.#settingsProcessor.bind(this), }); - await this._storage.load(); - log.debug("Loaded settings", this._storage.data, this._storage.path); - this._applyMappings(); - this._notifyChanges(); + await this.#storage.load(); + log.debug("Loaded settings", this.#storage.data, this.#storage.path); + this.#applyMappings(); + this.#notifyChanges(); } - _settingsProcessor(data) { + #settingsProcessor(data) { if ("lastCheck" in data) { - this._lastCheck = data.lastCheck; + this.#lastCheck = data.lastCheck; } else { data.lastCheck = 0; } @@ -410,56 +420,56 @@ class _OnionAliasStore { } return true; }); - this._channels = channels; + this.#channels = channels; return data; } - _saveSettings() { - if (this._storage === null) { + #saveSettings() { + if (this.#storage === null) { throw Error("Settings have not been loaded"); } - this._storage.data.lastCheck = this._lastCheck; - this._storage.data.channels = Array.from(this._channels.values(), ch => + this.#storage.data.lastCheck = this.#lastCheck; + this.#storage.data.channels = Array.from(this.#channels.values(), ch => ch.toJSON() ); - this._storage.saveSoon(); + this.#storage.saveSoon(); } - _addMapping(shortOnionHost, longOnionHost) { + #addMapping(shortOnionHost, longOnionHost) { const service = Cc["@torproject.org/onion-alias-service;1"].getService( Ci.IOnionAliasService ); service.addOnionAlias(shortOnionHost, longOnionHost); } - _clear() { + #clear() { const service = Cc["@torproject.org/onion-alias-service;1"].getService( Ci.IOnionAliasService ); service.clearOnionAliases(); } - _applyMappings() { - this._clear(); - for (const ch of this._channels.values()) { + #applyMappings() { + this.#clear(); + for (const ch of this.#channels.values()) { if (!ch.enabled) { continue; } for (const [short, long] of ch.mappings) { - this._addMapping(short, long); + this.#addMapping(short, long); } } } - async _periodicRulesetCheck() { + async #periodicRulesetCheck() { if (!this.enabled) { log.debug("Onion Aliases are disabled, not updating rulesets."); return; } log.debug("Begin scheduled ruleset update"); - this._lastCheck = Date.now(); + this.#lastCheck = Date.now(); let anyUpdated = false; - for (const ch of this._channels.values()) { + for (const ch of this.#channels.values()) { if (!ch.enabled) { log.debug(`Not updating ${ch.name} because not enabled`); continue; @@ -473,22 +483,22 @@ class _OnionAliasStore { } } if (anyUpdated) { - this._saveSettings(); - this._applyMappings(); - this._notifyChanges(); + this.#saveSettings(); + this.#applyMappings(); + this.#notifyChanges(); } else { log.debug("No channel has been updated, avoid saving"); } - this._scheduleCheck(_OnionAliasStore.RULESET_CHECK_INTERVAL); + this.#scheduleCheck(_OnionAliasStore.RULESET_CHECK_INTERVAL); } - async _startUpdates() { - // This is a "private" function, so we expect the callers to verify wheter + async #startUpdates() { + // This is a private function, so we expect the callers to verify whether // onion aliases are enabled. // Callees will also do, so we avoid an additional check here. - const dt = Date.now() - this._lastCheck; + const dt = Date.now() - this.#lastCheck; let force = false; - for (const ch of this._channels.values()) { + for (const ch of this.#channels.values()) { if (ch.enabled && !ch.currentTimestamp) { // Edited while being offline or some other error happened force = true; @@ -499,34 +509,34 @@ class _OnionAliasStore { log.debug( `Mappings are stale (${dt}), or force check requested (${force}), checking them immediately` ); - await this._periodicRulesetCheck(); + await this.#periodicRulesetCheck(); } else { - this._scheduleCheck(_OnionAliasStore.RULESET_CHECK_INTERVAL - dt); + this.#scheduleCheck(_OnionAliasStore.RULESET_CHECK_INTERVAL - dt); } } - _scheduleCheck(dt) { - if (this._rulesetTimeout) { + #scheduleCheck(dt) { + if (this.#rulesetTimeout) { log.warn("The previous update timeout was not null"); - clearTimeout(this._rulesetTimeout); + clearTimeout(this.#rulesetTimeout); } if (!this.enabled) { log.warn( "Ignoring the scheduling of a new check because the Onion Alias feature is currently disabled." ); - this._rulesetTimeout = null; + this.#rulesetTimeout = null; return; } log.debug(`Scheduling ruleset update in ${dt}`); - this._rulesetTimeout = setTimeout(() => { - this._rulesetTimeout = null; - this._periodicRulesetCheck(); + this.#rulesetTimeout = setTimeout(() => { + this.#rulesetTimeout = null; + this.#periodicRulesetCheck(); }, dt); } - _notifyChanges() { + #notifyChanges() { Services.obs.notifyObservers( - Array.from(this._channels.values(), ch => ch.toJSON()), + Array.from(this.#channels.values(), ch => ch.toJSON()), OnionAliasStoreTopics.ChannelsChanged ); } @@ -538,11 +548,16 @@ class _OnionAliasStore { observe(aSubject, aTopic) { if (aTopic === "nsPref:changed") { if (this.enabled) { - this._startUpdates(); - } else if (this._rulesetTimeout) { - clearTimeout(this._rulesetTimeout); - this._rulesetTimeout = null; + this.#startUpdates(); + } else if (this.#rulesetTimeout) { + clearTimeout(this.#rulesetTimeout); + this.#rulesetTimeout = null; } + } else if ( + aTopic === lazy.TorConnectTopics.BootstrapComplete && + this.enabled + ) { + this.#startUpdates(); } } } ===================================== browser/components/onionservices/moz.build ===================================== @@ -1,8 +1,11 @@ JAR_MANIFESTS += ["jar.mn"] EXTRA_JS_MODULES += [ - "OnionAliasStore.sys.mjs", "OnionLocationChild.sys.mjs", "OnionLocationParent.sys.mjs", +] + +MOZ_SRC_FILES += [ + "OnionAliasStore.sys.mjs", "TorRequestWatch.sys.mjs", ] ===================================== browser/components/rulesets/RulesetsParent.sys.mjs ===================================== @@ -1,9 +1,11 @@ -// Copyright (c) 2022, The Tor Project, Inc. +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import { OnionAliasStore, OnionAliasStoreTopics, -} from "resource:///modules/OnionAliasStore.sys.mjs"; +} from "moz-src:///browser/components/onionservices/OnionAliasStore.sys.mjs"; const kShowWarningPref = "torbrowser.rulesets.show_warning"; @@ -56,9 +58,10 @@ export class RulesetsParent extends JSWindowActorParent { return { showWarning: Services.prefs.getBoolPref(kShowWarningPref, true), }; - case "rulesets:set-channel": + case "rulesets:set-channel": { const ch = await OnionAliasStore.setChannel(message.data); return ch; + } case "rulesets:update-channel": // We need to catch any error in this way, because in case of an // exception, RPMSendQuery does not return on the other side ===================================== browser/modules/ClipboardPrivacy.sys.mjs ===================================== @@ -0,0 +1,178 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + AsyncShutdown: "resource://gre/modules/AsyncShutdown.sys.mjs", + PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", + setTimeout: "resource://gre/modules/Timer.sys.mjs", +}); + +/** + * Empty clipboard content from private windows on exit. + * + * See tor-browser#42154. + */ +export const ClipboardPrivacy = { + _lastClipboardHash: null, + _globalActivation: false, + _isPrivateClipboard: false, + _hasher: null, + _shuttingDown: false, + _log: null, + + _createTransferable() { + const trans = Cc["@mozilla.org/widget/transferable;1"].createInstance( + Ci.nsITransferable + ); + trans.init(null); + return trans; + }, + _computeClipboardHash() { + const flavors = ["text/x-moz-url", "text/plain"]; + if ( + !Services.clipboard.hasDataMatchingFlavors( + flavors, + Ci.nsIClipboard.kGlobalClipboard + ) + ) { + return null; + } + const trans = this._createTransferable(); + flavors.forEach(trans.addDataFlavor); + try { + Services.clipboard.getData(trans, Ci.nsIClipboard.kGlobalClipboard); + const clipboardContent = {}; + trans.getAnyTransferData({}, clipboardContent); + const { data } = clipboardContent.value.QueryInterface( + Ci.nsISupportsString + ); + const bytes = new TextEncoder().encode(data); + const hasher = (this._hasher ||= Cc[ + "@mozilla.org/security/hash;1" + ].createInstance(Ci.nsICryptoHash)); + hasher.init(hasher.SHA256); + hasher.update(bytes, bytes.length); + return hasher.finish(true); + } catch (e) {} + return null; + }, + + init() { + this._log = console.createInstance({ + prefix: "ClipboardPrivacy", + }); + this._lastClipboardHash = this._computeClipboardHash(); + + // Here we track changes in active window / application, + // by filtering focus events and window closures. + const handleActivation = (win, activation) => { + if (activation) { + if (!this._globalActivation) { + // focus changed within this window, bail out. + return; + } + this._globalActivation = false; + } else if (!Services.focus.activeWindow) { + // focus is leaving this window: + // let's track whether it remains within the browser. + lazy.setTimeout(() => { + this._globalActivation = !Services.focus.activeWindow; + }, 100); + } + + const checkClipboardContent = () => { + const clipboardHash = this._computeClipboardHash(); + if (clipboardHash !== this._lastClipboardHash) { + this._isPrivateClipboard = + !activation && + (lazy.PrivateBrowsingUtils.permanentPrivateBrowsing || + lazy.PrivateBrowsingUtils.isWindowPrivate(win)); + this._lastClipboardHash = clipboardHash; + this._log.debug( + `Clipboard changed: private ${this._isPrivateClipboard}, hash ${clipboardHash}.` + ); + } + }; + + if (win.closed) { + checkClipboardContent(); + } else { + // defer clipboard access on DOM events to work-around tor-browser#42306 + lazy.setTimeout(checkClipboardContent, 0); + } + }; + const focusListener = e => + e.isTrusted && handleActivation(e.currentTarget, e.type === "focusin"); + const initWindow = win => { + for (const e of ["focusin", "focusout"]) { + win.addEventListener(e, focusListener); + } + }; + for (const w of Services.ww.getWindowEnumerator()) { + initWindow(w); + } + Services.ww.registerNotification((win, event) => { + switch (event) { + case "domwindowopened": + initWindow(win); + break; + case "domwindowclosed": + handleActivation(win, false); + if ( + this._isPrivateClipboard && + lazy.PrivateBrowsingUtils.isWindowPrivate(win) && + (this._shuttingDown || + !Array.from(Services.ww.getWindowEnumerator()).find( + w => + lazy.PrivateBrowsingUtils.isWindowPrivate(w) && + // We need to filter out the HIDDEN WebExtensions window, + // which might be private as well but is not UI-relevant. + !w.location.href.startsWith("chrome://extensions/") + )) + ) { + // no more private windows, empty private content if needed + this.emptyPrivate(); + } + } + }); + + lazy.AsyncShutdown.quitApplicationGranted.addBlocker( + "ClipboardPrivacy: removing private data", + () => { + this._shuttingDown = true; + this.emptyPrivate(); + } + ); + }, + emptyPrivate() { + if ( + this._isPrivateClipboard && + !Services.prefs.getBoolPref( + "browser.privatebrowsing.preserveClipboard", + false + ) && + this._lastClipboardHash === this._computeClipboardHash() + ) { + // nsIClipboard.emptyClipboard() does nothing in Wayland: + // we'll set an empty string as a work-around. + const trans = this._createTransferable(); + const flavor = "text/plain"; + trans.addDataFlavor(flavor); + const emptyString = Cc["@mozilla.org/supports-string;1"].createInstance( + Ci.nsISupportsString + ); + emptyString.data = ""; + trans.setTransferData(flavor, emptyString); + const { clipboard } = Services, + { kGlobalClipboard } = clipboard; + clipboard.setData(trans, null, kGlobalClipboard); + clipboard.emptyClipboard(kGlobalClipboard); + this._lastClipboardHash = null; + this._isPrivateClipboard = false; + this._log.info("Private clipboard emptied."); + } + }, +}; ===================================== browser/modules/moz.build ===================================== @@ -136,12 +136,10 @@ EXTRA_JS_MODULES += [ "PopupBlockerObserver.sys.mjs", "ProcessHangMonitor.sys.mjs", "Sanitizer.sys.mjs", - "SecurityLevelRestartNotification.sys.mjs", "SelectionChangedMenulist.sys.mjs", "SharingUtils.sys.mjs", "SiteDataManager.sys.mjs", "SitePermissions.sys.mjs", - "TorSettingsNotification.sys.mjs", "TorUIUtils.sys.mjs", "TransientPrefs.sys.mjs", "URILoadingHelper.sys.mjs", @@ -151,6 +149,9 @@ EXTRA_JS_MODULES += [ MOZ_SRC_FILES += [ "ContextId.sys.mjs", + "ClipboardPrivacy.sys.mjs", + "SecurityLevelRestartNotification.sys.mjs", + "TorSettingsNotification.sys.mjs", ] if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows": ===================================== dom/base/ContentAreaDropListener.sys.mjs ===================================== @@ -5,7 +5,7 @@ const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { - OpaqueDrag: "resource://gre/modules/DragDropFilter.sys.mjs", + OpaqueDrag: "moz-src:///toolkit/modules/DragDropFilter.sys.mjs", }); // This component is used for handling dragover and drop of urls. ===================================== toolkit/components/places/PlacesUtils.sys.mjs ===================================== @@ -12,7 +12,7 @@ const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { Bookmarks: "resource://gre/modules/Bookmarks.sys.mjs", History: "resource://gre/modules/History.sys.mjs", - OpaqueDrag: "resource://gre/modules/DragDropFilter.sys.mjs", + OpaqueDrag: "moz-src:///toolkit/modules/DragDropFilter.sys.mjs", PlacesSyncUtils: "resource://gre/modules/PlacesSyncUtils.sys.mjs", Sqlite: "resource://gre/modules/Sqlite.sys.mjs", }); ===================================== toolkit/components/tor-launcher/tor-launcher.manifest ===================================== @@ -1 +1,2 @@ category profile-after-change TorStartupService @torproject.org/tor-startup-service;1 +category browser-first-window-ready resource://gre/modules/TorProviderBuilder.sys.mjs TorProviderBuilder.firstWindowLoaded ===================================== toolkit/modules/moz.build ===================================== @@ -164,7 +164,6 @@ EXTRA_JS_MODULES += [ "DateTimePickerPanel.sys.mjs", "DeferredTask.sys.mjs", "DomainFrontedRequests.sys.mjs", - "DragDropFilter.sys.mjs", "E10SUtils.sys.mjs", "EventEmitter.sys.mjs", "FileUtils.sys.mjs", @@ -220,6 +219,10 @@ EXTRA_JS_MODULES += [ "WebChannel.sys.mjs", ] +MOZ_SRC_FILES += [ + "DragDropFilter.sys.mjs", +] + if CONFIG["MOZ_ASAN_REPORTER"]: EXTRA_JS_MODULES += [ "AsanReporter.sys.mjs", View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/d28d9f… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/d28d9f… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][base-browser-140.2.0esr-15.0-1] BB 43525: Skip Remote Settings for search engine customization.
by Pier Angelo Vendrame (@pierov) 08 Sep '25

08 Sep '25
Pier Angelo Vendrame pushed to branch base-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser Commits: a1886d8c by Pier Angelo Vendrame at 2025-09-08T11:57:50+02:00 BB 43525: Skip Remote Settings for search engine customization. Also, add some bundled search engines. - - - - - 9 changed files: - toolkit/components/search/AppProvidedSearchEngine.sys.mjs - toolkit/components/search/SearchEngineSelector.sys.mjs - + toolkit/components/search/content/base-browser-search-engine-icons.json - + toolkit/components/search/content/base-browser-search-engines.json - + toolkit/components/search/content/duckduckgo.ico - + toolkit/components/search/content/startpage-16.png - + toolkit/components/search/content/startpage-32.png - + toolkit/components/search/jar.mn - toolkit/components/search/moz.build Changes: ===================================== toolkit/components/search/AppProvidedSearchEngine.sys.mjs ===================================== @@ -116,6 +116,10 @@ class IconHandler { await this.#buildIconMap(); } + if (AppConstants.BASE_BROWSER_VERSION) { + return this.#iconMap.get(engineIdentifier); + } + let iconList = this.#iconMap.get(this.getKey(engineIdentifier)) || []; return iconList.filter(r => this.#identifierMatches(engineIdentifier, r.engineIdentifiers) @@ -132,29 +136,7 @@ class IconHandler { * source object or null of there is no icon with the supplied width. */ async createIconURL(iconRecord) { - let iconData; - try { - iconData = await this.#iconCollection.attachments.get(iconRecord); - } catch (ex) { - console.error(ex); - } - if (!iconData) { - console.warn("Unable to find the attachment for", iconRecord.id); - // Queue an update in case we haven't downloaded it yet. - this.#pendingUpdatesMap.set(iconRecord.id, iconRecord); - this.#maybeQueueIdle(); - return null; - } - - if (iconData.record.last_modified != iconRecord.last_modified) { - // The icon we have stored is out of date, queue an update so that we'll - // download the new icon. - this.#pendingUpdatesMap.set(iconRecord.id, iconRecord); - this.#maybeQueueIdle(); - } - return URL.createObjectURL( - new Blob([iconData.buffer], { type: iconRecord.attachment.mimetype }) - ); + return iconRecord.url; } QueryInterface = ChromeUtils.generateQI(["nsIObserver"]); @@ -238,27 +220,23 @@ class IconHandler { * Obtains the icon list from the remote settings collection. */ async #buildIconMap() { - let iconList = []; try { - iconList = await this.#iconCollection.get(); + this.#iconMap = new Map( + Object.entries( + await ( + await fetch( + "chrome://global/content/search/base-browser-search-engine-icons.json" + ) + ).json() + ) + ); } catch (ex) { console.error(ex); + this.#iconMap = null; } - if (!iconList.length) { + if (!this.#iconMap) { console.error("Failed to obtain search engine icon list records"); } - - this.#iconMap = new Map(); - for (let record of iconList) { - let keys = new Set(record.engineIdentifiers.map(this.getKey)); - for (let key of keys) { - if (this.#iconMap.has(key)) { - this.#iconMap.get(key).push(record); - } else { - this.#iconMap.set(key, [record]); - } - } - } } /** ===================================== toolkit/components/search/SearchEngineSelector.sys.mjs ===================================== @@ -2,6 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs"; + /** * @typedef {import("../uniffi-bindgen-gecko-js/components/generated/RustSearch.sys.mjs").SearchEngineSelector} RustSearchEngineSelector * We use "Rust" above to avoid conflict with the class name for the JavaScript wrapper. @@ -92,30 +94,15 @@ export class SearchEngineSelector { return this._getConfigurationPromise; } - this._getConfigurationPromise = Promise.all([ - this._getConfiguration(), - this._getConfigurationOverrides(), - ]); - let remoteSettingsData = await this._getConfigurationPromise; - this._configuration = remoteSettingsData[0]; - this._configurationOverrides = remoteSettingsData[1]; - delete this._getConfigurationPromise; - - if (!this._configuration?.length) { - throw Components.Exception( - "Failed to get engine data from Remote Settings", - Cr.NS_ERROR_UNEXPECTED - ); - } - - if (!this._listenerAdded) { - this._remoteConfig.on("sync", this._onConfigurationUpdated); - this._remoteConfigOverrides.on( - "sync", - this._onConfigurationOverridesUpdated - ); - this._listenerAdded = true; - } + let { promise, resolve } = Promise.withResolvers(); + this._getConfigurationPromise = promise; + this._configuration = await ( + await fetch( + "chrome://global/content/search/base-browser-search-engines.json" + ) + ).json(); + this._configurationOverrides = []; + resolve(this._configuration); if (lazy.SearchUtils.rustSelectorFeatureGate) { this.#selector.setSearchConfig( @@ -242,6 +229,12 @@ export class SearchEngineSelector { * The new configuration object */ _onConfigurationUpdated({ data: { current } }) { + // tor-browser#43525: Even though RemoteSettings are a no-op for us, we do + // not want them to interfere in any way. + if (AppConstants.BASE_BROWSER_VERSION) { + return; + } + this._configuration = current; if (lazy.SearchUtils.rustSelectorFeatureGate) { @@ -268,6 +261,12 @@ export class SearchEngineSelector { * The new configuration object */ _onConfigurationOverridesUpdated({ data: { current } }) { + // tor-browser#43525: Even though RemoteSettings are a no-op for us, we do + // not want them to interfere in any way. + if (AppConstants.BASE_BROWSER_VERSION) { + return; + } + this._configurationOverrides = current; if (lazy.SearchUtils.rustSelectorFeatureGate) { ===================================== toolkit/components/search/content/base-browser-search-engine-icons.json ===================================== @@ -0,0 +1,15 @@ +{ + "ddg": [ + { "url": "chrome://global/content/search/duckduckgo.ico", "imageSize": 32 } + ], + "startpage": [ + { + "url": "chrome://global/content/search/startpage-16.png", + "imageSize": 16 + }, + { + "url": "chrome://global/content/search/startpage-32.png", + "imageSize": 32 + } + ] +} ===================================== toolkit/components/search/content/base-browser-search-engines.json ===================================== @@ -0,0 +1,43 @@ +[ + { + "base": { + "aliases": ["duckduckgo", "ddg"], + "classification": "general", + "name": "DuckDuckGo", + "urls": { + "search": { + "base": "https://duckduckgo.com/", + "params": [], + "searchTermParamName": "q" + } + } + }, + "id": "04e99a38-13ee-47d8-8aa4-64482b3dea99", + "identifier": "ddg", + "recordType": "engine", + "variants": [{ "environment": { "allRegionsAndLocales": true } }] + }, + { + "base": { + "aliases": ["startpage", "sp"], + "classification": "general", + "name": "Startpage", + "urls": { + "search": { + "base": "https://www.startpage.com/sp/search", + "params": [], + "searchTermParamName": "q" + } + } + }, + "id": "927bbd9f-b2f3-48b4-8974-1c1148028f4d", + "identifier": "startpage", + "recordType": "engine", + "variants": [{ "environment": { "allRegionsAndLocales": true } }] + }, + { + "recordType": "defaultEngines", + "globalDefault": "ddg", + "globalDefaultPrivate": "ddg" + } +] ===================================== toolkit/components/search/content/duckduckgo.ico ===================================== Binary files /dev/null and b/toolkit/components/search/content/duckduckgo.ico differ ===================================== toolkit/components/search/content/startpage-16.png ===================================== Binary files /dev/null and b/toolkit/components/search/content/startpage-16.png differ ===================================== toolkit/components/search/content/startpage-32.png ===================================== Binary files /dev/null and b/toolkit/components/search/content/startpage-32.png differ ===================================== toolkit/components/search/jar.mn ===================================== @@ -0,0 +1,6 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +toolkit.jar: + content/global/search/ (content/*) ===================================== toolkit/components/search/moz.build ===================================== @@ -46,5 +46,7 @@ TESTING_JS_MODULES += [ "tests/SearchTestUtils.sys.mjs", ] +JAR_MANIFESTS += ["jar.mn"] + with Files("**"): BUG_COMPONENT = ("Firefox", "Search") View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/a1886d8… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/a1886d8… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/mullvad-browser][mullvad-browser-140.2.0esr-15.0-1] 4 commits: fixup! MB 213: Customize the search engines list
by Pier Angelo Vendrame (@pierov) 08 Sep '25

08 Sep '25
Pier Angelo Vendrame pushed to branch mullvad-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Mullvad Browser Commits: fd210716 by Pier Angelo Vendrame at 2025-09-08T11:52:36+02:00 fixup! MB 213: Customize the search engines list BB 43525: Skip Remote Settings for search engine customization. Drop some changes that we are not going to keep with the shared approach. - - - - - 0c345e48 by Pier Angelo Vendrame at 2025-09-08T11:53:16+02:00 dropme! MB 213: Customize the search engines list BB 43525: Skip Remote Settings for search engine customization. Prepare the tree for the new approach. - - - - - e95419fa by Pier Angelo Vendrame at 2025-09-08T11:53:17+02:00 BB 43525: Skip Remote Settings for search engine customization. Also, add some bundled search engines. - - - - - b80c84c1 by Pier Angelo Vendrame at 2025-09-08T11:53:17+02:00 amend! MB 213: Customize the search engines list MB 213: Customize the search engines list. - - - - - 6 changed files: - toolkit/components/search/AppProvidedSearchEngine.sys.mjs - toolkit/components/search/SearchEngineSelector.sys.mjs - toolkit/components/search/SearchService.sys.mjs - toolkit/components/search/content/mullvadBrowserSearchEngineIcons.json → toolkit/components/search/content/base-browser-search-engine-icons.json - + toolkit/components/search/content/base-browser-search-engines.json - − toolkit/components/search/content/mullvadBrowserSearchEngines.json Changes: ===================================== toolkit/components/search/AppProvidedSearchEngine.sys.mjs ===================================== @@ -116,7 +116,14 @@ class IconHandler { await this.#buildIconMap(); } - return this.#iconMap.get(engineIdentifier); + if (AppConstants.BASE_BROWSER_VERSION) { + return this.#iconMap.get(engineIdentifier); + } + + let iconList = this.#iconMap.get(this.getKey(engineIdentifier)) || []; + return iconList.filter(r => + this.#identifierMatches(engineIdentifier, r.engineIdentifiers) + ); } /** @@ -218,7 +225,7 @@ class IconHandler { Object.entries( await ( await fetch( - "chrome://global/content/search/mullvadBrowserSearchEngineIcons.json" + "chrome://global/content/search/base-browser-search-engine-icons.json" ) ).json() ) ===================================== toolkit/components/search/SearchEngineSelector.sys.mjs ===================================== @@ -2,6 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs"; + /** * @typedef {import("../uniffi-bindgen-gecko-js/components/generated/RustSearch.sys.mjs").SearchEngineSelector} RustSearchEngineSelector * We use "Rust" above to avoid conflict with the class name for the JavaScript wrapper. @@ -92,30 +94,15 @@ export class SearchEngineSelector { return this._getConfigurationPromise; } - this._getConfigurationPromise = Promise.all([ - this._getConfiguration(), - this._getConfigurationOverrides(), - ]); - let remoteSettingsData = await this._getConfigurationPromise; - this._configuration = remoteSettingsData[0]; - this._configurationOverrides = remoteSettingsData[1]; - delete this._getConfigurationPromise; - - if (!this._configuration?.length) { - throw Components.Exception( - "Failed to get engine data from Remote Settings", - Cr.NS_ERROR_UNEXPECTED - ); - } - - if (!this._listenerAdded) { - this._remoteConfig.on("sync", this._onConfigurationUpdated); - this._remoteConfigOverrides.on( - "sync", - this._onConfigurationOverridesUpdated - ); - this._listenerAdded = true; - } + let { promise, resolve } = Promise.withResolvers(); + this._getConfigurationPromise = promise; + this._configuration = await ( + await fetch( + "chrome://global/content/search/base-browser-search-engines.json" + ) + ).json(); + this._configurationOverrides = []; + resolve(this._configuration); if (lazy.SearchUtils.rustSelectorFeatureGate) { this.#selector.setSearchConfig( @@ -242,6 +229,12 @@ export class SearchEngineSelector { * The new configuration object */ _onConfigurationUpdated({ data: { current } }) { + // tor-browser#43525: Even though RemoteSettings are a no-op for us, we do + // not want them to interfere in any way. + if (AppConstants.BASE_BROWSER_VERSION) { + return; + } + this._configuration = current; if (lazy.SearchUtils.rustSelectorFeatureGate) { @@ -268,6 +261,12 @@ export class SearchEngineSelector { * The new configuration object */ _onConfigurationOverridesUpdated({ data: { current } }) { + // tor-browser#43525: Even though RemoteSettings are a no-op for us, we do + // not want them to interfere in any way. + if (AppConstants.BASE_BROWSER_VERSION) { + return; + } + this._configurationOverrides = current; if (lazy.SearchUtils.rustSelectorFeatureGate) { ===================================== toolkit/components/search/SearchService.sys.mjs ===================================== @@ -25,7 +25,6 @@ ChromeUtils.defineESModuleGetters(lazy, { Region: "resource://gre/modules/Region.sys.mjs", RemoteSettings: "resource://services-settings/remote-settings.sys.mjs", SearchEngine: "moz-src:///toolkit/components/search/SearchEngine.sys.mjs", - // eslint-disable-next-line mozilla/valid-lazy SearchEngineSelector: "moz-src:///toolkit/components/search/SearchEngineSelector.sys.mjs", SearchSettings: "moz-src:///toolkit/components/search/SearchSettings.sys.mjs", @@ -579,7 +578,11 @@ export class SearchService { // Test-only function to reset just the engine selector so that it can // load a different configuration. - resetEngineSelector() {} + resetEngineSelector() { + this.#engineSelector = new lazy.SearchEngineSelector( + this.#handleConfigurationUpdated.bind(this) + ); + } resetToAppDefaultEngine() { let appDefaultEngine = this.appDefaultEngine; @@ -1420,6 +1423,10 @@ export class SearchService { // We need to catch the region being updated during initialization so we // start listening straight away. Services.obs.addObserver(this, lazy.Region.REGION_TOPIC); + + this.#engineSelector = new lazy.SearchEngineSelector( + this.#handleConfigurationUpdated.bind(this) + ); } /** @@ -1652,7 +1659,6 @@ export class SearchService { * Handles the search configuration being - adds a wait on the user * being idle, before the search engine update gets handled. */ - // eslint-disable-next-line no-unused-private-class-members #handleConfigurationUpdated() { if (this.#queuedIdle) { return; @@ -2622,12 +2628,21 @@ export class SearchService { // This is prefixed with _ rather than # because it is // called in test_remove_engine_notification_box.js async _fetchEngineSelectorEngines() { - const engines = await ( - await fetch( - "chrome://global/content/search/mullvadBrowserSearchEngines.json" - ) - ).json(); - return { engines, privateDefault: undefined }; + let searchEngineSelectorProperties = { + locale: Services.locale.appLocaleAsBCP47, + region: lazy.Region.home || "unknown", + channel: lazy.SearchUtils.MODIFIED_APP_CHANNEL, + experiment: this._experimentPrefValue, + distroID: lazy.SearchUtils.distroID ?? "", + }; + + for (let [key, value] of Object.entries(searchEngineSelectorProperties)) { + this._settings.setMetaDataAttribute(key, value); + } + + return this.#engineSelector.fetchEngineConfiguration( + searchEngineSelectorProperties + ); } #setDefaultFromSelector(refinedConfig) { ===================================== toolkit/components/search/content/mullvadBrowserSearchEngineIcons.json → toolkit/components/search/content/base-browser-search-engine-icons.json ===================================== @@ -1,27 +1,33 @@ { "ddg": [ - { "url": "chrome://global/content/search/duckduckgo.ico", "iconSize": 32 } + { "url": "chrome://global/content/search/duckduckgo.ico", "imageSize": 32 } ], "ddg-html": [ - { "url": "chrome://global/content/search/duckduckgo.ico", "iconSize": 32 } + { "url": "chrome://global/content/search/duckduckgo.ico", "imageSize": 32 } ], "mullvad-leta": [ - { "url": "chrome://global/content/search/mullvad-leta.svg", "iconSize": 16 } + { + "url": "chrome://global/content/search/mullvad-leta.svg", + "imageSize": 16 + } ], "mojeek": [ - { "url": "chrome://global/content/search/mojeek.ico", "iconSize": 32 } + { "url": "chrome://global/content/search/mojeek.ico", "imageSize": 32 } ], "brave": [ - { "url": "chrome://global/content/search/brave.svg", "iconSize": 16 } + { "url": "chrome://global/content/search/brave.svg", "imageSize": 16 } ], "startpage": [ { "url": "chrome://global/content/search/startpage-16.png", - "iconSize": 16 + "imageSize": 16 }, - { "url": "chrome://global/content/search/startpage-32.png", "iconSize": 32 } + { + "url": "chrome://global/content/search/startpage-32.png", + "imageSize": 32 + } ], "metager": [ - { "url": "chrome://global/content/search/metager.ico", "iconSize": 196 } + { "url": "chrome://global/content/search/metager.ico", "imageSize": 196 } ] } ===================================== toolkit/components/search/content/base-browser-search-engines.json ===================================== @@ -0,0 +1,133 @@ +[ + { + "base": { + "aliases": ["mullvad-leta", "leta", "mullvad", "ml"], + "classification": "general", + "name": "Mullvad Leta", + "urls": { + "search": { + "base": "https://leta.mullvad.net/", + "params": [], + "searchTermParamName": "q" + } + } + }, + "id": "ee88d691-6d7a-4adb-9fec-5a205565505a", + "identifier": "mullvad-leta", + "recordType": "engine", + "variants": [{ "environment": { "allRegionsAndLocales": true } }] + }, + { + "base": { + "aliases": ["duckduckgo", "ddg"], + "classification": "general", + "name": "DuckDuckGo", + "urls": { + "search": { + "base": "https://duckduckgo.com/", + "params": [], + "searchTermParamName": "q" + } + } + }, + "id": "04e99a38-13ee-47d8-8aa4-64482b3dea99", + "identifier": "ddg", + "recordType": "engine", + "variants": [{ "environment": { "allRegionsAndLocales": true } }] + }, + { + "base": { + "aliases": ["ddg-html", "duckduckgohtml", "ddgh"], + "classification": "general", + "name": "DuckDuckGo (HTML)", + "urls": { + "search": { + "base": "https://html.duckduckgo.com/html/", + "params": [], + "searchTermParamName": "q" + } + } + }, + "id": "98d8c84b-7455-431d-98b9-890e7bcc0041", + "identifier": "ddg-html", + "recordType": "engine", + "variants": [{ "environment": { "allRegionsAndLocales": true } }] + }, + { + "base": { + "aliases": ["mojeek", "mj"], + "classification": "general", + "name": "Mojeek", + "urls": { + "search": { + "base": "https://www.mojeek.com/search", + "params": [], + "searchTermParamName": "q" + } + } + }, + "id": "10df12ac-2b39-4aa9-8845-d5b35d5bb70c", + "identifier": "mojeek", + "recordType": "engine", + "variants": [{ "environment": { "allRegionsAndLocales": true } }] + }, + { + "base": { + "aliases": ["brave", "bv"], + "classification": "general", + "name": "Brave Search", + "urls": { + "search": { + "base": "https://search.brave.com/search", + "params": [], + "searchTermParamName": "q" + } + } + }, + "id": "f479314b-030b-49a8-a2fe-7e1c5d1d9071", + "identifier": "brave", + "recordType": "engine", + "variants": [{ "environment": { "allRegionsAndLocales": true } }] + }, + { + "base": { + "aliases": ["startpage", "sp"], + "classification": "general", + "name": "Startpage", + "urls": { + "search": { + "base": "https://www.startpage.com/sp/search", + "params": [], + "searchTermParamName": "q" + } + } + }, + "id": "927bbd9f-b2f3-48b4-8974-1c1148028f4d", + "identifier": "startpage", + "recordType": "engine", + "variants": [{ "environment": { "allRegionsAndLocales": true } }] + }, + { + "base": { + "aliases": ["metager", "mg"], + "classification": "general", + "name": "MetaGer", + "urls": { + "search": { + "base": "https://metager.org/meta/meta.ger3", + "params": [], + "searchTermParamName": "eingabe" + } + } + }, + "id": "a9d07d93-469c-4bf4-8dd1-fa137f1cc85f", + "identifier": "metager", + "recordType": "engine", + "variants": [{ "environment": { "allRegionsAndLocales": true } }] + }, + { + "recordType": "defaultEngines", + "globalDefault": "mullvad-leta", + "globalDefaultPrivate": "mullvad-leta" + } +] ===================================== toolkit/components/search/content/mullvadBrowserSearchEngines.json deleted ===================================== @@ -1,114 +0,0 @@ -[ - { - "aliases": ["mullvad-leta", "leta", "mullvad", "ml"], - "name": "Mullvad Leta", - "urls": { - "search": { - "base": "https://leta.mullvad.net/", - "params": [], - "searchTermParamName": "q" - } - }, - "id": "ee88d691-6d7a-4adb-9fec-5a205565505a", - "identifier": "mullvad-leta", - "recordType": "engine", - "orderHint": 100, - "variants": [] - }, - { - "aliases": ["duckduckgo", "ddg"], - "name": "DuckDuckGo", - "urls": { - "search": { - "base": "https://duckduckgo.com/", - "params": [], - "searchTermParamName": "q" - } - }, - "id": "04e99a38-13ee-47d8-8aa4-64482b3dea99", - "identifier": "ddg", - "recordType": "engine", - "orderHint": 90, - "variants": [] - }, - { - "aliases": ["ddg-html", "duckduckgohtml", "ddgh"], - "name": "DuckDuckGo (HTML)", - "urls": { - "search": { - "base": "https://html.duckduckgo.com/html/", - "params": [], - "searchTermParamName": "q" - } - }, - "id": "98d8c84b-7455-431d-98b9-890e7bcc0041", - "identifier": "ddg-html", - "recordType": "engine", - "orderHint": 80, - "variants": [] - }, - { - "aliases": ["mojeek", "mj"], - "name": "Mojeek", - "urls": { - "search": { - "base": "https://www.mojeek.com/search", - "params": [], - "searchTermParamName": "q" - } - }, - "id": "10df12ac-2b39-4aa9-8845-d5b35d5bb70c", - "identifier": "mojeek", - "recordType": "engine", - "orderHint": 70, - "variants": [] - }, - { - "aliases": ["brave", "bv"], - "name": "Brave Search", - "urls": { - "search": { - "base": "https://search.brave.com/search", - "params": [], - "searchTermParamName": "q" - } - }, - "id": "f479314b-030b-49a8-a2fe-7e1c5d1d9071", - "identifier": "brave", - "recordType": "engine", - "orderHint": 60, - "variants": [] - }, - { - "aliases": ["startpage", "sp"], - "name": "Startpage", - "urls": { - "search": { - "base": "https://www.startpage.com/sp/search", - "params": [], - "searchTermParamName": "q" - } - }, - "id": "049f86fd-28fe-4389-910f-aac28f07d745", - "identifier": "startpage", - "recordType": "engine", - "orderHint": 50, - "variants": [] - }, - { - "aliases": ["metager", "mg"], - "name": "MetaGer", - "urls": { - "search": { - "base": "https://metager.org/meta/meta.ger3", - "params": [], - "searchTermParamName": "eingabe" - } - }, - "id": "a9d07d93-469c-4bf4-8dd1-fa137f1cc85f", - "identifier": "metager", - "recordType": "engine", - "orderHint": 40, - "variants": [] - } -] View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/ac… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/ac… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][tor-browser-140.2.0esr-15.0-1] 3 commits: dropme! TB 42891: Set the bundled search engine for Tor Browser.
by Pier Angelo Vendrame (@pierov) 08 Sep '25

08 Sep '25
Pier Angelo Vendrame pushed to branch tor-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser Commits: 2404a7c1 by Pier Angelo Vendrame at 2025-09-08T11:39:58+02:00 dropme! TB 42891: Set the bundled search engine for Tor Browser. BB 43525: Skip Remote Settings for search engine customization. Undo some changes to this commit, as they need to be moved to Base Browser. - - - - - 10cd8e31 by Pier Angelo Vendrame at 2025-09-08T11:39:58+02:00 BB 43525: Skip Remote Settings for search engine customization. Also, add some bundled search engines. - - - - - d28d9f49 by Pier Angelo Vendrame at 2025-09-08T11:39:59+02:00 amend! TB 42891: Set the bundled search engine for Tor Browser. TB 42891: Set the bundled search engine for Tor Browser. - - - - - 4 changed files: - toolkit/components/search/AppProvidedSearchEngine.sys.mjs - toolkit/components/search/SearchEngineSelector.sys.mjs - toolkit/components/search/content/torBrowserSearchEngineIcons.json → toolkit/components/search/content/base-browser-search-engine-icons.json - toolkit/components/search/content/torBrowserSearchEngines.json → toolkit/components/search/content/base-browser-search-engines.json Changes: ===================================== toolkit/components/search/AppProvidedSearchEngine.sys.mjs ===================================== @@ -116,8 +116,10 @@ class IconHandler { await this.#buildIconMap(); } - return this.#iconMap.get(engineIdentifier); - // eslint-disable-next-line no-unreachable + if (AppConstants.BASE_BROWSER_VERSION) { + return this.#iconMap.get(engineIdentifier); + } + let iconList = this.#iconMap.get(this.getKey(engineIdentifier)) || []; return iconList.filter(r => this.#identifierMatches(engineIdentifier, r.engineIdentifiers) @@ -223,7 +225,7 @@ class IconHandler { Object.entries( await ( await fetch( - "chrome://global/content/search/torBrowserSearchEngineIcons.json" + "chrome://global/content/search/base-browser-search-engine-icons.json" ) ).json() ) ===================================== toolkit/components/search/SearchEngineSelector.sys.mjs ===================================== @@ -97,7 +97,9 @@ export class SearchEngineSelector { let { promise, resolve } = Promise.withResolvers(); this._getConfigurationPromise = promise; this._configuration = await ( - await fetch("chrome://global/content/search/torBrowserSearchEngines.json") + await fetch( + "chrome://global/content/search/base-browser-search-engines.json" + ) ).json(); this._configurationOverrides = []; resolve(this._configuration); ===================================== toolkit/components/search/content/torBrowserSearchEngineIcons.json → toolkit/components/search/content/base-browser-search-engine-icons.json ===================================== @@ -1,15 +1,9 @@ { "ddg": [ - { - "url": "chrome://global/content/search/duckduckgo.ico", - "imageSize": 32 - } + { "url": "chrome://global/content/search/duckduckgo.ico", "imageSize": 32 } ], "ddg-onion": [ - { - "url": "chrome://global/content/search/duckduckgo.ico", - "imageSize": 32 - } + { "url": "chrome://global/content/search/duckduckgo.ico", "imageSize": 32 } ], "startpage": [ { @@ -32,9 +26,6 @@ } ], "wikipedia": [ - { - "url": "chrome://global/content/search/wikipedia.ico", - "imageSize": 32 - } + { "url": "chrome://global/content/search/wikipedia.ico", "imageSize": 32 } ] } ===================================== toolkit/components/search/content/torBrowserSearchEngines.json → toolkit/components/search/content/base-browser-search-engines.json ===================================== @@ -15,13 +15,7 @@ "id": "04e99a38-13ee-47d8-8aa4-64482b3dea99", "identifier": "ddg", "recordType": "engine", - "variants": [ - { - "environment": { - "allRegionsAndLocales": true - } - } - ] + "variants": [{ "environment": { "allRegionsAndLocales": true } }] }, { "base": { @@ -39,13 +33,7 @@ "id": "1e431da4-a60c-4411-9251-a95a841d451f", "identifier": "ddg-onion", "recordType": "engine", - "variants": [ - { - "environment": { - "allRegionsAndLocales": true - } - } - ] + "variants": [{ "environment": { "allRegionsAndLocales": true } }] }, { "base": { @@ -63,13 +51,7 @@ "id": "927bbd9f-b2f3-48b4-8974-1c1148028f4d", "identifier": "startpage", "recordType": "engine", - "variants": [ - { - "environment": { - "allRegionsAndLocales": true - } - } - ] + "variants": [{ "environment": { "allRegionsAndLocales": true } }] }, { "base": { @@ -87,13 +69,7 @@ "id": "e7eaba8d-6b9e-43fb-a799-b01b096c03ff", "identifier": "startpage-onion", "recordType": "engine", - "variants": [ - { - "environment": { - "allRegionsAndLocales": true - } - } - ] + "variants": [{ "environment": { "allRegionsAndLocales": true } }] }, { "base": { @@ -111,13 +87,7 @@ "id": "7f6d23c2-191e-483e-af3a-ce6451e3a8dd", "identifier": "wikipedia", "recordType": "engine", - "variants": [ - { - "environment": { - "allRegionsAndLocales": true - } - } - ] + "variants": [{ "environment": { "allRegionsAndLocales": true } }] }, { "recordType": "defaultEngines", View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/d244ff… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/d244ff… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/mullvad-browser][mullvad-browser-140.2.0esr-15.0-1] BB 43664: Automatically check the PBM checkbox when in always-on PBM.
by Pier Angelo Vendrame (@pierov) 05 Sep '25

05 Sep '25
Pier Angelo Vendrame pushed to branch mullvad-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Mullvad Browser Commits: ac67b549 by Pier Angelo Vendrame at 2025-09-05T18:56:43+02:00 BB 43664: Automatically check the PBM checkbox when in always-on PBM. - - - - - 1 changed file: - browser/base/content/browser-addons.js Changes: ===================================== browser/base/content/browser-addons.js ===================================== @@ -20,6 +20,7 @@ ChromeUtils.defineESModuleGetters(lazy, { ExtensionPermissions: "resource://gre/modules/ExtensionPermissions.sys.mjs", OriginControls: "resource://gre/modules/ExtensionPermissions.sys.mjs", PERMISSION_L10N: "resource://gre/modules/ExtensionPermissionMessages.sys.mjs", + PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", SITEPERMS_ADDON_TYPE: "resource://gre/modules/addons/siteperms-addon-utils.sys.mjs", }); @@ -466,7 +467,9 @@ customElements.define( this.notification.options.customElementOptions; let checkboxEl = this.ownerDocument.createElement("moz-checkbox"); - checkboxEl.checked = grantPrivateBrowsingAllowed; + checkboxEl.checked = + grantPrivateBrowsingAllowed || + lazy.PrivateBrowsingUtils.permanentPrivateBrowsing; checkboxEl.addEventListener("change", () => { // NOTE: the popupnotification instances will be reused // and so the callback function is destructured here to View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/ac6… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/ac6… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][base-browser-140.2.0esr-15.0-1] BB 43664: Automatically check the PBM checkbox when in always-on PBM.
by Pier Angelo Vendrame (@pierov) 05 Sep '25

05 Sep '25
Pier Angelo Vendrame pushed to branch base-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser Commits: d0b3fa67 by Pier Angelo Vendrame at 2025-09-05T18:56:10+02:00 BB 43664: Automatically check the PBM checkbox when in always-on PBM. - - - - - 1 changed file: - browser/base/content/browser-addons.js Changes: ===================================== browser/base/content/browser-addons.js ===================================== @@ -20,6 +20,7 @@ ChromeUtils.defineESModuleGetters(lazy, { ExtensionPermissions: "resource://gre/modules/ExtensionPermissions.sys.mjs", OriginControls: "resource://gre/modules/ExtensionPermissions.sys.mjs", PERMISSION_L10N: "resource://gre/modules/ExtensionPermissionMessages.sys.mjs", + PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", SITEPERMS_ADDON_TYPE: "resource://gre/modules/addons/siteperms-addon-utils.sys.mjs", }); @@ -466,7 +467,9 @@ customElements.define( this.notification.options.customElementOptions; let checkboxEl = this.ownerDocument.createElement("moz-checkbox"); - checkboxEl.checked = grantPrivateBrowsingAllowed; + checkboxEl.checked = + grantPrivateBrowsingAllowed || + lazy.PrivateBrowsingUtils.permanentPrivateBrowsing; checkboxEl.addEventListener("change", () => { // NOTE: the popupnotification instances will be reused // and so the callback function is destructured here to View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/d0b3fa6… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/d0b3fa6… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][tor-browser-140.2.0esr-15.0-1] BB 43664: Automatically check the PBM checkbox when in always-on PBM.
by Pier Angelo Vendrame (@pierov) 05 Sep '25

05 Sep '25
Pier Angelo Vendrame pushed to branch tor-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser Commits: d244ff5a by Pier Angelo Vendrame at 2025-09-04T18:30:26+02:00 BB 43664: Automatically check the PBM checkbox when in always-on PBM. - - - - - 1 changed file: - browser/base/content/browser-addons.js Changes: ===================================== browser/base/content/browser-addons.js ===================================== @@ -20,6 +20,7 @@ ChromeUtils.defineESModuleGetters(lazy, { ExtensionPermissions: "resource://gre/modules/ExtensionPermissions.sys.mjs", OriginControls: "resource://gre/modules/ExtensionPermissions.sys.mjs", PERMISSION_L10N: "resource://gre/modules/ExtensionPermissionMessages.sys.mjs", + PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", SITEPERMS_ADDON_TYPE: "resource://gre/modules/addons/siteperms-addon-utils.sys.mjs", }); @@ -466,7 +467,9 @@ customElements.define( this.notification.options.customElementOptions; let checkboxEl = this.ownerDocument.createElement("moz-checkbox"); - checkboxEl.checked = grantPrivateBrowsingAllowed; + checkboxEl.checked = + grantPrivateBrowsingAllowed || + lazy.PrivateBrowsingUtils.permanentPrivateBrowsing; checkboxEl.addEventListener("change", () => { // NOTE: the popupnotification instances will be reused // and so the callback function is destructured here to View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/d244ff5… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/d244ff5… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser-build][main] MB 463: Fix typo in MimeType entry in .desktop file included in deb/rpm package
by boklm (@boklm) 04 Sep '25

04 Sep '25
boklm pushed to branch main at The Tor Project / Applications / tor-browser-build Commits: 4c8683ec by Nicolas Vigier at 2025-09-04T16:03:43+02:00 MB 463: Fix typo in MimeType entry in .desktop file included in deb/rpm package - - - - - 1 changed file: - projects/linux-packages/browser.desktop.in Changes: ===================================== projects/linux-packages/browser.desktop.in ===================================== @@ -10,6 +10,6 @@ Icon=[% c("var/system_pkg/pkg_name") %] StartupNotify=true StartupWMClass=[% c("var/display_name") %] [% IF ! c("var/tor-browser") -%] -MimeType=text/html;text/xml;application/xhtml_xml;x-scheme-handler/http;x-scheme-handler/https; +MimeType=text/html;text/xml;application/xhtml+xml;x-scheme-handler/http;x-scheme-handler/https; [% END -%] Terminal=false View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/4… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/4… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
  • ← Newer
  • 1
  • ...
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • ...
  • 819
  • Older →

HyperKitty Powered by HyperKitty version 1.3.12.