tor-commits
Threads by month
- ----- 2026 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- 1 participants
- 216095 discussions
[Git][tpo/applications/tor-browser][tor-browser-128.4.0esr-14.5-1] fixup! Adding issue and merge request templates
by morgan (@morgan) 30 Oct '24
by morgan (@morgan) 30 Oct '24
30 Oct '24
morgan pushed to branch tor-browser-128.4.0esr-14.5-1 at The Tor Project / Applications / Tor Browser
Commits:
35ef7d82 by Henry Wilkes at 2024-10-29T21:24:47+00:00
fixup! Adding issue and merge request templates
Bug 43262: Update QA desktop checklist to include testing saved keys and
their preferences.
- - - - -
1 changed file:
- .gitlab/issue_templates/QA - Desktop.md
Changes:
=====================================
.gitlab/issue_templates/QA - Desktop.md
=====================================
@@ -135,6 +135,10 @@ Manual QA test check-list for major desktop releases. Please copy/paste form int
- [ ] Onion-Location pill
- [ ] Client authentication
- You can create an ephemeral client-auth onion-service using [onion share](https://onionshare.org)
+ - [ ] Remember key option saves the key between sessions.
+ - [ ] Saved keys are viewable in preferences (privacy).
+ - [ ] Can remove individual keys.
+ - [ ] Can remove all keys at once.
- [ ] Onion service errors
- [ ] invalid onion: http://invalid.onion
- [ ] onion offline: http://wfdn32ds656ycma5gvrh7duvdvxbg2ygzr3no3ijsya25qm6nnko4iqd.onion/
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/35ef7d8…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/35ef7d8…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser-build][main] Update release prep issue templates (Tor Browser Legacy)
by morgan (@morgan) 30 Oct '24
by morgan (@morgan) 30 Oct '24
30 Oct '24
morgan pushed to branch main at The Tor Project / Applications / tor-browser-build
Commits:
344327b6 by Nicolas Vigier at 2024-10-29T21:19:49+00:00
Update release prep issue templates (Tor Browser Legacy)
Add missing step when manually deploying update responses for
legacy-only release.
- - - - -
1 changed file:
- .gitlab/issue_templates/Release Prep - Tor Browser Legacy.md
Changes:
=====================================
.gitlab/issue_templates/Release Prep - Tor Browser Legacy.md
=====================================
@@ -251,6 +251,22 @@ popd
```bash
make torbrowser-update_responses-release
```
+ - [ ] Commit new update responses to tor-browser-update-responses.git:
+ - [ ] Run:
+ ```bash
+ updaterespdir=/path/to/tor-browser-update-responses.git
+ cp torbrowser/release/update-responses/update-responses-release-${TOR_BROWSER_VERSION}.tar "$updaterespdir"
+ cd "$updaterespdir"
+ git pull
+ rm -Rf update_3/release
+ tar -C update_3 update-responses-release-${TOR_BROWSER_VERSION}.tar
+ rm update-responses-release-${TOR_BROWSER_VERSION}.tar
+ git add update_3/release
+ git commit -m "release: new version, ${TOR_BROWSER_VERSION}"
+ git push
+ # print the commit hash and copy past it for the next step
+ git show -s --format=%H
+ ```
- On `staticiforme.torproject.org`, deploy new update responses:
- **NOTE**: for now this is a bit janky, we should somehow update the workflow to be a bit less hacky
- [ ] Edit an existing `deploy_update_responses-release.sh` script in your `HOME` directory with the newly pushed commit hash
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/3…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/3…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser][tor-browser-128.4.0esr-14.5-1] fixup! [android] Modify UI/UX
by morgan (@morgan) 30 Oct '24
by morgan (@morgan) 30 Oct '24
30 Oct '24
morgan pushed to branch tor-browser-128.4.0esr-14.5-1 at The Tor Project / Applications / Tor Browser
Commits:
474dd858 by cypherpunks1 at 2024-10-29T21:13:24+00:00
fixup! [android] Modify UI/UX
Bug 43241: Improve hiding non-private tab features on Android
- - - - -
3 changed files:
- mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt
- mobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt
- mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt
Changes:
=====================================
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt
=====================================
@@ -218,13 +218,13 @@ open class DefaultToolbarMenu(
onItemTapped.invoke(ToolbarMenu.Item.NewTorCircuit)
}
- //private val historyItem = BrowserMenuImageText(
- // context.getString(R.string.library_history),
- // R.drawable.ic_history,
- // primaryTextColor()
- //) {
- // onItemTapped.invoke(ToolbarMenu.Item.History)
- //}
+ private val historyItem = BrowserMenuImageText(
+ context.getString(R.string.library_history),
+ R.drawable.ic_history,
+ primaryTextColor(),
+ ) {
+ onItemTapped.invoke(ToolbarMenu.Item.History)
+ }
private val downloadsItem = BrowserMenuImageText(
context.getString(R.string.library_downloads),
@@ -419,7 +419,7 @@ open class DefaultToolbarMenu(
newCircuitItem,
BrowserMenuDivider(),
bookmarksItem,
- //historyItem,
+ if (context.settings().shouldDisableNormalMode) null else historyItem,
downloadsItem,
passwordsItem,
extensionsItem,
=====================================
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt
=====================================
@@ -131,13 +131,13 @@ class HomeMenu(
onItemTapped.invoke(Item.Bookmarks)
}
- // val historyItem = BrowserMenuImageText(
- // context.getString(R.string.library_history),
- // R.drawable.ic_history,
- // primaryTextColor,
- // ) {
- // onItemTapped.invoke(Item.History)
- // }
+ val historyItem = BrowserMenuImageText(
+ context.getString(R.string.library_history),
+ R.drawable.ic_history,
+ primaryTextColor,
+ ) {
+ onItemTapped.invoke(Item.History)
+ }
val downloadsItem = BrowserMenuImageText(
context.getString(R.string.library_downloads),
@@ -228,7 +228,7 @@ class HomeMenu(
val menuItems = listOfNotNull(
bookmarksItem,
- //historyItem,
+ if (context.settings().shouldDisableNormalMode) null else historyItem,
downloadsItem,
passwordsItem,
// extensionsItem,
=====================================
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt
=====================================
@@ -251,9 +251,11 @@ class SettingsFragment : PreferenceFragmentCompat() {
getString(R.string.delete_browsing_data_quit_off)
}
- val tabSettingsPreference =
- requirePreference<Preference>(R.string.pref_key_tabs)
- tabSettingsPreference.summary = context?.settings()?.getTabTimeoutString()
+ if (!settings.shouldDisableNormalMode) {
+ val tabSettingsPreference =
+ requirePreference<Preference>(R.string.pref_key_tabs)
+ tabSettingsPreference.summary = context?.settings()?.getTabTimeoutString()
+ }
// val autofillPreference = requirePreference<Preference>(R.string.pref_key_credit_cards)
// autofillPreference.title = if (settings.addressFeature) {
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/474dd85…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/474dd85…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser][tor-browser-128.4.0esr-14.5-1] 3 commits: fixup! Bug 16940: After update, load local change notes.
by morgan (@morgan) 30 Oct '24
by morgan (@morgan) 30 Oct '24
30 Oct '24
morgan pushed to branch tor-browser-128.4.0esr-14.5-1 at The Tor Project / Applications / Tor Browser
Commits:
6d2b4add by Henry Wilkes at 2024-10-29T21:02:40+00:00
fixup! Bug 16940: After update, load local change notes.
Bug 42186: Revert the entire commit.
- - - - -
201d50e6 by Henry Wilkes at 2024-10-29T21:02:40+00:00
fixup! Add TorStrings module for localization
Bug 42186: Drop about:tbupdate.
- - - - -
b4b207fa by Henry Wilkes at 2024-10-29T21:02:40+00:00
fixup! Bug 7494: Create local home page for TBB.
Bug 42186: Move override page logic to about:tor commit.
- - - - -
15 changed files:
- − browser/actors/AboutTBUpdateChild.sys.mjs
- − browser/actors/AboutTBUpdateParent.sys.mjs
- browser/actors/moz.build
- − browser/base/content/abouttbupdate/aboutTBUpdate.css
- − browser/base/content/abouttbupdate/aboutTBUpdate.js
- − browser/base/content/abouttbupdate/aboutTBUpdate.xhtml
- browser/base/content/browser.js
- browser/base/jar.mn
- browser/components/BrowserContentHandler.sys.mjs
- browser/components/BrowserGlue.sys.mjs
- browser/components/about/AboutRedirector.cpp
- browser/components/about/components.conf
- toolkit/modules/RemotePageAccessManager.sys.mjs
- − toolkit/torbutton/chrome/locale/en-US/aboutTBUpdate.dtd
- toolkit/torbutton/jar.mn
Changes:
=====================================
browser/actors/AboutTBUpdateChild.sys.mjs deleted
=====================================
@@ -1,8 +0,0 @@
-// Copyright (c) 2020, The Tor Project, Inc.
-// See LICENSE for licensing information.
-//
-// vim: set sw=2 sts=2 ts=8 et syntax=javascript:
-
-import { RemotePageChild } from "resource://gre/actors/RemotePageChild.sys.mjs";
-
-export class AboutTBUpdateChild extends RemotePageChild {}
=====================================
browser/actors/AboutTBUpdateParent.sys.mjs deleted
=====================================
@@ -1,128 +0,0 @@
-// Copyright (c) 2020, The Tor Project, Inc.
-// See LICENSE for licensing information.
-//
-// vim: set sw=2 sts=2 ts=8 et syntax=javascript:
-
-import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
-
-const kRequestUpdateMessageName = "FetchUpdateData";
-
-/**
- * This code provides services to the about:tbupdate page. Whenever
- * about:tbupdate needs to do something chrome-privileged, it sends a
- * message that's handled here. It is modeled after Mozilla's about:home
- * implementation.
- */
-export class AboutTBUpdateParent extends JSWindowActorParent {
- async receiveMessage(aMessage) {
- if (aMessage.name == kRequestUpdateMessageName) {
- return this.getReleaseNoteInfo();
- }
- return undefined;
- }
-
- get moreInfoURL() {
- try {
- return Services.prefs.getCharPref("torbrowser.post_update.url");
- } catch (e) {}
-
- // Use the default URL as a fallback.
- return Services.urlFormatter.formatURLPref("startup.homepage_override_url");
- }
-
- // Read the text from the beginning of the changelog file that is located
- // at TorBrowser/Docs/ChangeLog.txt (or,
- // TorBrowser.app/Contents/Resources/TorBrowser/Docs/ on macOS, to support
- // Gatekeeper signing) and return an object that contains the following
- // properties:
- // version e.g., Tor Browser 8.5
- // releaseDate e.g., March 31 2019
- // releaseNotes details of changes (lines 2 - end of ChangeLog.txt)
- // We attempt to parse the first line of ChangeLog.txt to extract the
- // version and releaseDate. If parsing fails, we return the entire first
- // line in version and omit releaseDate.
- async getReleaseNoteInfo() {
- let info = { moreInfoURL: this.moreInfoURL };
-
- try {
- // "XREExeF".parent is the directory that contains firefox, i.e.,
- // Browser/ or, TorBrowser.app/Contents/MacOS/ on macOS.
- let f = Services.dirsvc.get("XREExeF", Ci.nsIFile).parent;
- if (AppConstants.platform === "macosx") {
- f = f.parent;
- f.append("Resources");
- }
- f.append("TorBrowser");
- f.append("Docs");
- f.append("ChangeLog.txt");
-
- // NOTE: We load in the entire file, but only use the first few lines
- // before the first blank line.
- const logLines = (await IOUtils.readUTF8(f.path))
- .replace(/\n\r?\n.*/ms, "")
- .split(/\n\r?/);
-
- // Read the first line to get the version and date.
- // Assume everything after the last "-" is the date.
- const firstLine = logLines.shift();
- const match = firstLine?.match(/(.*)-+(.*)/);
- if (match) {
- info.version = match[1].trim();
- info.releaseDate = match[2].trim();
- } else {
- // No date.
- info.version = firstLine?.trim();
- }
-
- // We want to read the rest of the release notes as a tree. Each entry
- // will contain the text for that line.
- // We choose a negative index for the top node of this tree to ensure no
- // line will appear less indented.
- const topEntry = { indent: -1, children: undefined };
- let prevEntry = topEntry;
-
- for (let line of logLines) {
- const indent = line.match(/^ */)[0];
- line = line.trim();
- if (line.startsWith("*")) {
- // Treat as a bullet point.
- let entry = {
- text: line.replace(/^\*\s/, ""),
- indent: indent.length,
- };
- let parentEntry;
- if (entry.indent > prevEntry.indent) {
- // A sub-list of the previous item.
- prevEntry.children = [];
- parentEntry = prevEntry;
- } else {
- // Same list or end of sub-list.
- // Search for the first parent whose indent comes before ours.
- parentEntry = prevEntry.parent;
- while (entry.indent <= parentEntry.indent) {
- parentEntry = parentEntry.parent;
- }
- }
- entry.parent = parentEntry;
- parentEntry.children.push(entry);
- prevEntry = entry;
- } else if (prevEntry === topEntry) {
- // Unexpected, missing bullet point on first line.
- // Place as its own bullet point instead, and set as prevEntry for the
- // next loop.
- prevEntry = { text: line, indent: indent.length, parent: topEntry };
- topEntry.children = [prevEntry];
- } else {
- // Append to the previous bullet point.
- prevEntry.text += ` ${line}`;
- }
- }
-
- info.releaseNotes = topEntry.children;
- } catch (e) {
- console.error(e);
- }
-
- return info;
- }
-}
=====================================
browser/actors/moz.build
=====================================
@@ -90,9 +90,3 @@ FINAL_TARGET_FILES.actors += [
BROWSER_CHROME_MANIFESTS += [
"test/browser/browser.toml",
]
-
-if CONFIG["BASE_BROWSER_UPDATE"]:
- FINAL_TARGET_FILES.actors += [
- "AboutTBUpdateChild.sys.mjs",
- "AboutTBUpdateParent.sys.mjs",
- ]
=====================================
browser/base/content/abouttbupdate/aboutTBUpdate.css deleted
=====================================
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2019, The Tor Project, Inc.
- * See LICENSE for licensing information.
- *
- * vim: set sw=2 sts=2 ts=8 et syntax=css:
- */
-
-:root {
- --abouttor-text-color: white;
- --abouttor-bg-toron-color: #420C5D;
-}
-
-body {
- font-family: Helvetica, Arial, sans-serif;
- color: var(--abouttor-text-color);
- background-color: var(--abouttor-bg-toron-color);
- margin-block: 40px;
- margin-inline: 50px;
- display: grid;
- grid-template-columns: auto auto;
- align-items: baseline;
- gap: 40px 50px;
-}
-
-body > *:not([hidden]) {
- display: contents;
-}
-
-.label-column {
- grid-column: 1;
-}
-
-.content {
- grid-column: 2;
-}
-
-.content.en-US-content {
- font-family: monospace;
- line-height: 1.4;
-}
-
-.label-column, .content {
- margin: 0;
- padding: 0;
- font-size: 1rem;
- font-weight: normal;
-}
-
-a {
- color: inherit;
-}
-
-.no-line-break {
- white-space: nowrap;
-}
-
-ul {
- padding-inline: 1em 0;
-}
-
-h3, h4 {
- font-size: 1.1rem;
- font-weight: bold;
-}
-
-h3.build-system-heading {
- font-size: 1.5rem;
- font-weight: normal;
- margin-block-start: 3em;
-}
=====================================
browser/base/content/abouttbupdate/aboutTBUpdate.js deleted
=====================================
@@ -1,110 +0,0 @@
-// Copyright (c) 2020, The Tor Project, Inc.
-// See LICENSE for licensing information.
-//
-// vim: set sw=2 sts=2 ts=8 et syntax=javascript:
-
-/* eslint-env mozilla/remote-page */
-
-/**
- * An object representing a bullet point in the release notes.
- *
- * typedef {Object} ReleaseBullet
- * @property {string} text - The text for this bullet point.
- * @property {?Array<ReleaseBullet>} children - A sub-list of bullet points.
- */
-
-/**
- * Fill an element with the given list of release bullet points.
- *
- * @param {Element} container - The element to fill with bullet points.
- * @param {Array<ReleaseBullet>} bulletPoints - The list of bullet points.
- * @param {string} [childTag="h3"] - The element tag name to use for direct
- * children. Initially, the children are h3 sub-headings.
- */
-function fillReleaseNotes(container, bulletPoints, childTag = "h3") {
- for (const { text, children } of bulletPoints) {
- const childEl = document.createElement(childTag);
- // Keep dashes like "[tor-browser]" on the same line by nowrapping the word.
- for (const [index, part] of text.split(/(\S+-\S+)/).entries()) {
- if (!part) {
- continue;
- }
- const span = document.createElement("span");
- span.textContent = part;
- span.classList.toggle("no-line-break", index % 2);
- childEl.appendChild(span);
- }
- container.appendChild(childEl);
- if (children) {
- if (childTag == "h3" && text.toLowerCase() === "build system") {
- // Special case: treat the "Build System" heading's children as
- // sub-headings.
- childEl.classList.add("build-system-heading");
- fillReleaseNotes(container, children, "h4");
- } else {
- const listEl = document.createElement("ul");
- fillReleaseNotes(listEl, children, "li");
- if (childTag == "li") {
- // Insert within the "li" element.
- childEl.appendChild(listEl);
- } else {
- container.appendChild(listEl);
- }
- }
- }
- }
-}
-
-/**
- * Set the content for the specified container, or hide it if we have no
- * content.
- *
- * @template C
- * @param {string} containerId - The id for the container.
- * @param {?C} content - The content for this container, or a falsey value if
- * the container has no content.
- * @param {function(contentEl: Elemenet, content: C)} [fillContent] - A function
- * to fill the ".content" contentEl with the given 'content'. If unspecified,
- * the 'content' will become the contentEl's textContent.
- */
-function setContent(containerId, content, fillContent) {
- const container = document.getElementById(containerId);
- if (!content) {
- container.hidden = true;
- return;
- }
- const contentEl = container.querySelector(".content");
- // Release notes are only in English.
- contentEl.setAttribute("lang", "en-US");
- contentEl.setAttribute("dir", "ltr");
- contentEl.classList.add("en-US-content");
- if (fillContent) {
- fillContent(contentEl, content);
- } else {
- contentEl.textContent = content;
- }
-}
-
-/**
- * Callback when we receive the update details.
- *
- * @param {Object} aData - The update details.
- * @param {?string} aData.version - The update version.
- * @param {?string} aData.releaseDate - The release date.
- * @param {?string} aData.moreInfoURL - A URL for more info.
- * @param {?Array<ReleaseBullet>} aData.releaseNotes - Release notes as bullet
- * points.
- */
-function onUpdate(aData) {
- setContent("version-row", aData.version);
- setContent("releasedate-row", aData.releaseDate);
- setContent("releasenotes", aData.releaseNotes, fillReleaseNotes);
-
- if (aData.moreInfoURL) {
- document.getElementById("infolink").setAttribute("href", aData.moreInfoURL);
- } else {
- document.getElementById("fullinfo").hidden = true;
- }
-}
-
-RPMSendQuery("FetchUpdateData").then(onUpdate);
=====================================
browser/base/content/abouttbupdate/aboutTBUpdate.xhtml deleted
=====================================
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!DOCTYPE html [ <!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
-%htmlDTD;
-<!ENTITY % tbUpdateDTD SYSTEM "chrome://browser/locale/aboutTBUpdate.dtd">
-%tbUpdateDTD; ]>
-
-<html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta
- http-equiv="Content-Security-Policy"
- content="default-src chrome:; object-src 'none'"
- />
- <title>&aboutTBUpdate.changelogTitle;</title>
- <link
- rel="stylesheet"
- type="text/css"
- href="chrome://browser/content/abouttbupdate/aboutTBUpdate.css"
- />
- <script
- src="chrome://browser/content/abouttbupdate/aboutTBUpdate.js"
- type="text/javascript"
- />
- <!-- Hack: we are not using Fluent translations in this page (yet), but we use
- - this tag so it sets up the page automatically for us. -->
- <link rel="localization" href="branding/brand.ftl" />
- </head>
- <body>
- <!-- NOTE: We don't use the <dl>, <dt> and <dd> elements to form name-value
- - pairs because this semantics is relatively new, whilst firefox
- - currently still maps these to the more limited "definitionlist", "term"
- - and "definition" roles. -->
- <div id="version-row">
- <span class="label-column">&aboutTBUpdate.version;</span>
- <span class="content"></span>
- </div>
- <div id="releasedate-row">
- <span class="label-column">&aboutTBUpdate.releaseDate;</span>
- <span class="content"></span>
- </div>
- <div id="fullinfo">
- <p class="content">
- &aboutTBUpdate.linkPrefix;<a id="infolink">&aboutTBUpdate.linkLabel;</a
- >&aboutTBUpdate.linkSuffix;
- </p>
- </div>
- <section id="releasenotes">
- <h2 class="label-column">&aboutTBUpdate.releaseNotes;</h2>
- <div class="content"></div>
- </section>
- </body>
-</html>
=====================================
browser/base/content/browser.js
=====================================
@@ -771,10 +771,6 @@ if (Services.prefs.getBoolPref("browser.profiles.enabled")) {
gInitialPages.push("about:profilemanager");
}
-if (AppConstants.BASE_BROWSER_UPDATE) {
- gInitialPages.push("about:tbupdate");
-}
-
function isInitialPage(url) {
if (!(url instanceof Ci.nsIURI)) {
try {
=====================================
browser/base/jar.mn
=====================================
@@ -33,11 +33,6 @@ browser.jar:
content/browser/aboutTabCrashed.css (content/aboutTabCrashed.css)
content/browser/aboutTabCrashed.js (content/aboutTabCrashed.js)
content/browser/aboutTabCrashed.xhtml (content/aboutTabCrashed.xhtml)
-#ifdef BASE_BROWSER_UPDATE
- content/browser/abouttbupdate/aboutTBUpdate.xhtml (content/abouttbupdate/aboutTBUpdate.xhtml)
- content/browser/abouttbupdate/aboutTBUpdate.js (content/abouttbupdate/aboutTBUpdate.js)
- content/browser/abouttbupdate/aboutTBUpdate.css (content/abouttbupdate/aboutTBUpdate.css)
-#endif
content/browser/blanktab.html (content/blanktab.html)
content/browser/browser.css (content/browser.css)
content/browser/browser.js (content/browser.js)
=====================================
browser/components/BrowserContentHandler.sys.mjs
=====================================
@@ -783,16 +783,6 @@ nsBrowserContentHandler.prototype = {
// into account because that requires waiting for the session file
// to be read. If a crash occurs after updating, before restarting,
// we may open the startPage in addition to restoring the session.
- //
- // Tor Browser: Instead of opening the post-update "override page"
- // directly, we ensure that about:tor will be opened in a special
- // mode that notifies the user that their browser was updated.
- // The about:tor page will provide a link to the override page
- // where the user can learn more about the update, as well as a
- // link to the Tor Browser changelog page (about:tbupdate). The
- // override page URL comes from the openURL attribute within the
- // updates.xml file or, if no showURL action is present, from the
- // startup.homepage_override_url pref.
willRestoreSession =
lazy.SessionStartup.isAutomaticRestoreEnabled();
@@ -887,6 +877,13 @@ nsBrowserContentHandler.prototype = {
old_forkVersion
);
if (overridePage && AppConstants.BASE_BROWSER_UPDATE) {
+ // Tor Browser: Instead of opening the post-update "override page"
+ // directly, we ensure that about:tor will be opened, which should
+ // notify the user that their browser was updated.
+ //
+ // The overridePage comes from the openURL attribute within the
+ // updates.xml file or, if no showURL action is present, from the
+ // startup.homepage_override_url pref.
Services.prefs.setCharPref(
"torbrowser.post_update.url",
overridePage
=====================================
browser/components/BrowserGlue.sys.mjs
=====================================
@@ -1022,21 +1022,6 @@ let JSWINDOWACTORS = {
},
};
-if (AppConstants.BASE_BROWSER_UPDATE) {
- JSWINDOWACTORS.AboutTBUpdate = {
- parent: {
- esModuleURI: "resource:///actors/AboutTBUpdateParent.sys.mjs",
- },
- child: {
- esModuleURI: "resource:///actors/AboutTBUpdateChild.sys.mjs",
- events: {
- DOMWindowCreated: { capture: true },
- },
- },
- matches: ["about:tbupdate"],
- };
-}
-
ChromeUtils.defineLazyGetter(
lazy,
"WeaveService",
=====================================
browser/components/about/AboutRedirector.cpp
=====================================
@@ -166,13 +166,6 @@ static const RedirEntry kRedirMap[] = {
nsIAboutModule::URI_MUST_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT |
nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS |
nsIAboutModule::HIDE_FROM_ABOUTABOUT},
-#ifdef BASE_BROWSER_UPDATE
- {"tbupdate", "chrome://browser/content/abouttbupdate/aboutTBUpdate.xhtml",
- nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
- nsIAboutModule::URI_MUST_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT |
- nsIAboutModule::HIDE_FROM_ABOUTABOUT |
- nsIAboutModule::IS_SECURE_CHROME_UI},
-#endif
// The correct URI must be obtained by GetManualChromeURI
{"manual", "about:blank",
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
=====================================
browser/components/about/components.conf
=====================================
@@ -35,9 +35,6 @@ pages = [
'welcomeback',
]
-if defined('BASE_BROWSER_UPDATE'):
- pages.append('tbupdate')
-
Classes = [
{
'cid': '{7e4bb6ad-2fc4-4dc6-89ef-23e8e5ccf980}',
=====================================
toolkit/modules/RemotePageAccessManager.sys.mjs
=====================================
@@ -237,9 +237,6 @@ export let RemotePageAccessManager = {
RPMAddMessageListener: ["*"],
RPMRemoveMessageListener: ["*"],
},
- "about:tbupdate": {
- RPMSendQuery: ["FetchUpdateData"],
- },
"about:torconnect": {
RPMAddMessageListener: [
"torconnect:state-change",
=====================================
toolkit/torbutton/chrome/locale/en-US/aboutTBUpdate.dtd deleted
=====================================
@@ -1,18 +0,0 @@
-<!-- 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/. -->
-
-<!ENTITY aboutTBUpdate.changelogTitle "Tor Browser Changelog">
-<!ENTITY aboutTBUpdate.version "Version">
-<!ENTITY aboutTBUpdate.releaseDate "Release Date">
-<!ENTITY aboutTBUpdate.releaseNotes "Release Notes">
-<!-- LOCALIZATION NOTE: the following entities are used to create the link to
- - obtain more information about the latest update.
- - The markup on the page looks like this:
- - &aboutTBUpdate.linkPrefix;<a href="...">&aboutTBUpdate.linkLabel;</a>&aboutTBUpdate.linkSuffix;
- - So, linkPrefix is what precedes the link, linkLabel is the link itself,
- - and linkSuffix is a text after the link. -->
-<!ENTITY aboutTBUpdate.linkPrefix "For the most up-to-date information about this release, ">
-<!ENTITY aboutTBUpdate.linkLabel "visit our website">
-<!ENTITY aboutTBUpdate.linkSuffix ".">
=====================================
toolkit/torbutton/jar.mn
=====================================
@@ -7,8 +7,5 @@ torbutton.jar:
# browser branding
% override chrome://branding/locale/brand.properties chrome://torbutton/locale/brand.properties
-# Strings for the about:tbupdate page
-% override chrome://browser/locale/aboutTBUpdate.dtd chrome://torbutton/locale/aboutTBUpdate.dtd
-
% locale torbutton en-US %locale/en-US/
locale/en-US/ (chrome/locale/en-US/*)
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/50cede…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/50cede…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser][base-browser-128.4.0esr-14.5-1] Bug 42739: Use the brand name for profile error messages.
by morgan (@morgan) 30 Oct '24
by morgan (@morgan) 30 Oct '24
30 Oct '24
morgan pushed to branch base-browser-128.4.0esr-14.5-1 at The Tor Project / Applications / Tor Browser
Commits:
b64a2539 by Henry Wilkes at 2024-10-29T20:48:07+00:00
Bug 42739: Use the brand name for profile error messages.
Some messages in profileSelection.properties use gAppData->name as
variable inputs. However, gAppData->name is still "Firefox" for our
base-browser builds, rather than the user-facing browser name. We swap
these instances with the displayed brand name instead.
- - - - -
2 changed files:
- toolkit/xre/ProfileReset.cpp
- toolkit/xre/nsAppRunner.cpp
Changes:
=====================================
toolkit/xre/ProfileReset.cpp
=====================================
@@ -23,8 +23,8 @@
using namespace mozilla;
-extern const XREAppData* gAppData;
-
+static const char kBrandProperties[] =
+ "chrome://branding/locale/brand.properties";
static const char kProfileProperties[] =
"chrome://mozapps/locale/profile/profileSelection.properties";
@@ -49,12 +49,21 @@ nsresult ProfileResetCleanup(nsToolkitProfileService* aService,
mozilla::components::StringBundle::Service();
if (!sbs) return NS_ERROR_FAILURE;
+ nsCOMPtr<nsIStringBundle> brandBundle;
+ Unused << sbs->CreateBundle(kBrandProperties, getter_AddRefs(brandBundle));
+ if (!brandBundle) return NS_ERROR_FAILURE;
+
nsCOMPtr<nsIStringBundle> sb;
Unused << sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
if (!sb) return NS_ERROR_FAILURE;
- NS_ConvertUTF8toUTF16 appName(gAppData->name);
- AutoTArray<nsString, 2> params = {appName, appName};
+ nsAutoString appName;
+ rv = brandBundle->GetStringFromName("brandShortName", appName);
+ if (NS_FAILED(rv)) return rv;
+
+ AutoTArray<nsString, 2> params;
+ params.AppendElement(appName);
+ params.AppendElement(appName);
nsAutoString resetBackupDirectoryName;
=====================================
toolkit/xre/nsAppRunner.cpp
=====================================
@@ -2597,6 +2597,8 @@ nsresult LaunchChild(bool aBlankCommandLine, bool aTryExec) {
return NS_ERROR_LAUNCHED_CHILD_PROCESS;
}
+static const char kBrandProperties[] =
+ "chrome://branding/locale/brand.properties";
static const char kProfileProperties[] =
"chrome://mozapps/locale/profile/profileSelection.properties";
@@ -2666,12 +2668,20 @@ static nsresult ProfileMissingDialog(nsINativeAppSupport* aNative) {
mozilla::components::StringBundle::Service();
NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
+ nsCOMPtr<nsIStringBundle> brandBundle;
+ sbs->CreateBundle(kBrandProperties, getter_AddRefs(brandBundle));
+ NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
nsCOMPtr<nsIStringBundle> sb;
sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
- NS_ConvertUTF8toUTF16 appName(gAppData->name);
- AutoTArray<nsString, 2> params = {appName, appName};
+ nsAutoString appName;
+ rv = brandBundle->GetStringFromName("brandShortName", appName);
+ NS_ENSURE_SUCCESS(rv, NS_ERROR_ABORT);
+
+ AutoTArray<nsString, 2> params;
+ params.AppendElement(appName);
+ params.AppendElement(appName);
// profileMissing
nsAutoString missingMessage;
@@ -2733,12 +2743,21 @@ static ReturnAbortOnError ProfileLockedDialog(nsIFile* aProfileDir,
mozilla::components::StringBundle::Service();
NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
+ nsCOMPtr<nsIStringBundle> brandBundle;
+ sbs->CreateBundle(kBrandProperties, getter_AddRefs(brandBundle));
+ NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
nsCOMPtr<nsIStringBundle> sb;
sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
- NS_ConvertUTF8toUTF16 appName(gAppData->name);
- AutoTArray<nsString, 3> params = {appName, appName, appName};
+ nsAutoString appName;
+ rv = brandBundle->GetStringFromName("brandShortName", appName);
+ NS_ENSURE_SUCCESS(rv, NS_ERROR_ABORT);
+
+ AutoTArray<nsString, 3> params;
+ params.AppendElement(appName);
+ params.AppendElement(appName);
+ params.AppendElement(appName);
nsAutoString killMessage;
#ifndef XP_MACOSX
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/b64a253…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/b64a253…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser][tor-browser-128.4.0esr-14.5-1] 3 commits: fixup! Bug 14631: Improve profile access error messages.
by morgan (@morgan) 30 Oct '24
by morgan (@morgan) 30 Oct '24
30 Oct '24
morgan pushed to branch tor-browser-128.4.0esr-14.5-1 at The Tor Project / Applications / Tor Browser
Commits:
1f0bfac8 by Henry Wilkes at 2024-10-29T20:11:45+00:00
fixup! Bug 14631: Improve profile access error messages.
Bug 42739: Revert patch for "Improve profile access error messages."
- - - - -
8cef0b28 by Henry Wilkes at 2024-10-29T20:11:45+00:00
fixup! Add TorStrings module for localization
Bug 42739: Drop profile access error strings.
- - - - -
50cede2a by Henry Wilkes at 2024-10-29T20:11:45+00:00
Bug 42739: Use the brand name for profile error messages.
Some messages in profileSelection.properties use gAppData->name as
variable inputs. However, gAppData->name is still "Firefox" for our
base-browser builds, rather than the user-facing browser name. We swap
these instances with the displayed brand name instead.
- - - - -
6 changed files:
- toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties
- toolkit/profile/nsToolkitProfileService.cpp
- toolkit/profile/nsToolkitProfileService.h
- − toolkit/torbutton/chrome/locale/en-US/torbutton.properties
- toolkit/xre/ProfileReset.cpp
- toolkit/xre/nsAppRunner.cpp
Changes:
=====================================
toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties
=====================================
@@ -12,11 +12,6 @@ restartMessageUnlocker=%S is already running, but is not responding. The old %S
restartMessageNoUnlockerMac=A copy of %S is already open. Only one copy of %S can be open at a time.
restartMessageUnlockerMac=A copy of %S is already open. The running copy of %S will quit in order to open this one.
-# LOCALIZATION NOTE (profileProblemTitle, profileReadOnly, profileReadOnlyMac, profileAccessDenied): Messages displayed when the browser profile cannot be accessed or written to. %S is the application name.
-profileProblemTitle=%S Profile Problem
-profileReadOnly=You cannot run %S from a read-only file system. Please copy %S to another location before trying to use it.
-profileReadOnlyMac=You cannot run %S from a read-only file system. Please copy %S to your Desktop or Applications folder before trying to use it.
-profileAccessDenied=%S does not have permission to access the profile. Please adjust your file system permissions and try again.
# Profile manager
# LOCALIZATION NOTE (profileTooltip): First %S is the profile name, second %S is the path to the profile folder.
profileTooltip=Profile: ‘%S’ — Path: ‘%S’
=====================================
toolkit/profile/nsToolkitProfileService.cpp
=====================================
@@ -1261,10 +1261,9 @@ nsToolkitProfileService::SelectStartupProfile(
}
bool wasDefault;
- ProfileStatus profileStatus;
nsresult rv =
SelectStartupProfile(&argc, argv.get(), aIsResetting, aRootDir, aLocalDir,
- aProfile, aDidCreate, &wasDefault, profileStatus);
+ aProfile, aDidCreate, &wasDefault);
// Since we were called outside of the normal startup path complete any
// startup tasks.
@@ -1299,8 +1298,7 @@ static void SaltProfileName(nsACString& aName);
nsresult nsToolkitProfileService::SelectStartupProfile(
int* aArgc, char* aArgv[], bool aIsResetting, nsIFile** aRootDir,
nsIFile** aLocalDir, nsIToolkitProfile** aProfile, bool* aDidCreate,
- bool* aWasDefaultSelection, ProfileStatus& aProfileStatus) {
- aProfileStatus = PROFILE_STATUS_OK;
+ bool* aWasDefaultSelection) {
if (mStartupProfileSelected) {
return NS_ERROR_ALREADY_INITIALIZED;
}
@@ -1393,13 +1391,6 @@ nsresult nsToolkitProfileService::SelectStartupProfile(
rv = XRE_GetFileFromPath(arg, getter_AddRefs(lf));
NS_ENSURE_SUCCESS(rv, rv);
- aProfileStatus = CheckProfileWriteAccess(lf);
- if (PROFILE_STATUS_OK != aProfileStatus) {
- NS_ADDREF(*aRootDir = lf);
- NS_ADDREF(*aLocalDir = lf);
- return NS_ERROR_FAILURE;
- }
-
// Make sure that the profile path exists and it's a directory.
bool exists;
rv = lf->Exists(&exists);
@@ -2259,47 +2250,3 @@ nsresult XRE_GetFileFromPath(const char* aPath, nsIFile** aResult) {
# error Platform-specific logic needed here.
#endif
}
-
-// Check for write permission to the profile directory by trying to create a
-// new file (after ensuring that no file with the same name exists).
-ProfileStatus nsToolkitProfileService::CheckProfileWriteAccess(
- nsIFile* aProfileDir) {
-#if defined(XP_UNIX)
- constexpr auto writeTestFileName = u".parentwritetest"_ns;
-#else
- constexpr auto writeTestFileName = u"parent.writetest"_ns;
-#endif
-
- nsCOMPtr<nsIFile> writeTestFile;
- nsresult rv = aProfileDir->Clone(getter_AddRefs(writeTestFile));
- if (NS_SUCCEEDED(rv)) rv = writeTestFile->Append(writeTestFileName);
-
- if (NS_SUCCEEDED(rv)) {
- bool doesExist = false;
- rv = writeTestFile->Exists(&doesExist);
- if (NS_SUCCEEDED(rv) && doesExist) rv = writeTestFile->Remove(true);
- }
-
- if (NS_SUCCEEDED(rv)) {
- rv = writeTestFile->Create(nsIFile::NORMAL_FILE_TYPE, 0666);
- (void)writeTestFile->Remove(true);
- }
-
- ProfileStatus status =
- NS_SUCCEEDED(rv) ? PROFILE_STATUS_OK : PROFILE_STATUS_OTHER_ERROR;
- if (NS_ERROR_FILE_ACCESS_DENIED == rv)
- status = PROFILE_STATUS_ACCESS_DENIED;
- else if (NS_ERROR_FILE_READ_ONLY == rv)
- status = PROFILE_STATUS_READ_ONLY;
-
- return status;
-}
-
-ProfileStatus nsToolkitProfileService::CheckProfileWriteAccess(
- nsIToolkitProfile* aProfile) {
- nsCOMPtr<nsIFile> profileDir;
- nsresult rv = aProfile->GetRootDir(getter_AddRefs(profileDir));
- if (NS_FAILED(rv)) return PROFILE_STATUS_OTHER_ERROR;
-
- return CheckProfileWriteAccess(profileDir);
-}
=====================================
toolkit/profile/nsToolkitProfileService.h
=====================================
@@ -17,14 +17,6 @@
#include "nsProfileLock.h"
#include "nsINIParser.h"
-enum ProfileStatus {
- PROFILE_STATUS_OK,
- PROFILE_STATUS_ACCESS_DENIED,
- PROFILE_STATUS_READ_ONLY,
- PROFILE_STATUS_IS_LOCKED,
- PROFILE_STATUS_OTHER_ERROR
-};
-
class nsToolkitProfile final
: public nsIToolkitProfile,
public mozilla::LinkedListElement<RefPtr<nsToolkitProfile>> {
@@ -81,13 +73,10 @@ class nsToolkitProfileService final : public nsIToolkitProfileService {
nsresult SelectStartupProfile(int* aArgc, char* aArgv[], bool aIsResetting,
nsIFile** aRootDir, nsIFile** aLocalDir,
nsIToolkitProfile** aProfile, bool* aDidCreate,
- bool* aWasDefaultSelection,
- ProfileStatus& aProfileStatus);
+ bool* aWasDefaultSelection);
nsresult CreateResetProfile(nsIToolkitProfile** aNewProfile);
nsresult ApplyResetProfile(nsIToolkitProfile* aOldProfile);
void CompleteStartup();
- static ProfileStatus CheckProfileWriteAccess(nsIToolkitProfile* aProfile);
- static ProfileStatus CheckProfileWriteAccess(nsIFile* aProfileDir);
private:
friend class nsToolkitProfile;
=====================================
toolkit/torbutton/chrome/locale/en-US/torbutton.properties deleted
=====================================
@@ -1,11 +0,0 @@
-# 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/.
-
-# Profile/startup error messages.
-# LOCALIZATION NOTE: %S is the application name.
-profileProblemTitle=%S Profile Problem
-profileReadOnly=You cannot run %S from a read-only file system. Please copy %S to another location before trying to use it.
-profileReadOnlyMac=You cannot run %S from a read-only file system. Please copy %S to your Desktop or Applications folder before trying to use it.
-profileAccessDenied=%S does not have permission to access the profile. Please adjust your file system permissions and try again.
=====================================
toolkit/xre/ProfileReset.cpp
=====================================
@@ -23,8 +23,8 @@
using namespace mozilla;
-extern const XREAppData* gAppData;
-
+static const char kBrandProperties[] =
+ "chrome://branding/locale/brand.properties";
static const char kProfileProperties[] =
"chrome://mozapps/locale/profile/profileSelection.properties";
@@ -49,12 +49,21 @@ nsresult ProfileResetCleanup(nsToolkitProfileService* aService,
mozilla::components::StringBundle::Service();
if (!sbs) return NS_ERROR_FAILURE;
+ nsCOMPtr<nsIStringBundle> brandBundle;
+ Unused << sbs->CreateBundle(kBrandProperties, getter_AddRefs(brandBundle));
+ if (!brandBundle) return NS_ERROR_FAILURE;
+
nsCOMPtr<nsIStringBundle> sb;
Unused << sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
if (!sb) return NS_ERROR_FAILURE;
- NS_ConvertUTF8toUTF16 appName(gAppData->name);
- AutoTArray<nsString, 2> params = {appName, appName};
+ nsAutoString appName;
+ rv = brandBundle->GetStringFromName("brandShortName", appName);
+ if (NS_FAILED(rv)) return rv;
+
+ AutoTArray<nsString, 2> params;
+ params.AppendElement(appName);
+ params.AppendElement(appName);
nsAutoString resetBackupDirectoryName;
=====================================
toolkit/xre/nsAppRunner.cpp
=====================================
@@ -2599,91 +2599,8 @@ nsresult LaunchChild(bool aBlankCommandLine, bool aTryExec) {
return NS_ERROR_LAUNCHED_CHILD_PROCESS;
}
-static nsresult GetOverrideStringBundleForLocale(nsIStringBundleService* aSBS,
- const char* aTorbuttonURI,
- const char* aLocale,
- nsIStringBundle** aResult) {
- NS_ENSURE_ARG(aSBS);
- NS_ENSURE_ARG(aTorbuttonURI);
- NS_ENSURE_ARG(aLocale);
- NS_ENSURE_ARG(aResult);
-
- const char* kFormatStr =
- "jar:%s!/chrome/torbutton/locale/%s/torbutton.properties";
- nsPrintfCString strBundleURL(kFormatStr, aTorbuttonURI, aLocale);
- nsresult rv = aSBS->CreateBundle(strBundleURL.get(), aResult);
- NS_ENSURE_SUCCESS(rv, rv);
-
- // To ensure that we have a valid string bundle, try to retrieve a string
- // that we know exists.
- nsAutoString val;
- rv = (*aResult)->GetStringFromName("profileProblemTitle", val);
- if (!NS_SUCCEEDED(rv)) *aResult = nullptr; // No good. Discard it.
-
- return rv;
-}
-
-static void GetOverrideStringBundle(nsIStringBundleService* aSBS,
- nsIStringBundle** aResult) {
- if (!aSBS || !aResult) return;
-
- *aResult = nullptr;
-
- // Build Torbutton file URI string by starting from GREDir.
- RefPtr<nsXREDirProvider> dirProvider = nsXREDirProvider::GetSingleton();
- if (!dirProvider) return;
-
- nsCOMPtr<nsIFile> greDir = dirProvider->GetGREDir();
- if (!greDir) return;
-
- // Create file URI, extract as string, and append omni.ja relative path.
- nsCOMPtr<nsIURI> uri;
- nsAutoCString uriString;
- if (NS_FAILED(NS_NewFileURI(getter_AddRefs(uri), greDir)) ||
- NS_FAILED(uri->GetSpec(uriString))) {
- return;
- }
-
- uriString.Append("omni.ja");
-
- nsAutoCString userAgentLocale;
- if (!NS_SUCCEEDED(
- Preferences::GetCString("intl.locale.requested", userAgentLocale))) {
- return;
- }
-
- nsresult rv = GetOverrideStringBundleForLocale(
- aSBS, uriString.get(), userAgentLocale.get(), aResult);
- if (NS_FAILED(rv)) {
- // Try again using base locale, e.g., "en" vs. "en-US".
- int16_t offset = userAgentLocale.FindChar('-', 1);
- if (offset > 0) {
- nsAutoCString shortLocale(Substring(userAgentLocale, 0, offset));
- rv = GetOverrideStringBundleForLocale(aSBS, uriString.get(),
- shortLocale.get(), aResult);
- }
- }
-}
-
-static nsresult GetFormattedString(nsIStringBundle* aOverrideBundle,
- nsIStringBundle* aMainBundle,
- const char* aName,
- const nsTArray<nsString>& aParams,
- nsAString& aResult) {
- NS_ENSURE_ARG(aName);
-
- nsresult rv = NS_ERROR_FAILURE;
- if (aOverrideBundle) {
- rv = aOverrideBundle->FormatStringFromName(aName, aParams, aResult);
- }
-
- // If string was not found in override bundle, use main (browser) bundle.
- if (NS_FAILED(rv) && aMainBundle)
- rv = aMainBundle->FormatStringFromName(aName, aParams, aResult);
-
- return rv;
-}
-
+static const char kBrandProperties[] =
+ "chrome://branding/locale/brand.properties";
static const char kProfileProperties[] =
"chrome://mozapps/locale/profile/profileSelection.properties";
@@ -2753,12 +2670,20 @@ static nsresult ProfileMissingDialog(nsINativeAppSupport* aNative) {
mozilla::components::StringBundle::Service();
NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
+ nsCOMPtr<nsIStringBundle> brandBundle;
+ sbs->CreateBundle(kBrandProperties, getter_AddRefs(brandBundle));
+ NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
nsCOMPtr<nsIStringBundle> sb;
sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
- NS_ConvertUTF8toUTF16 appName(MOZ_APP_DISPLAYNAME);
- AutoTArray<nsString, 2> params = {appName, appName};
+ nsAutoString appName;
+ rv = brandBundle->GetStringFromName("brandShortName", appName);
+ NS_ENSURE_SUCCESS(rv, NS_ERROR_ABORT);
+
+ AutoTArray<nsString, 2> params;
+ params.AppendElement(appName);
+ params.AppendElement(appName);
// profileMissing
nsAutoString missingMessage;
@@ -2782,12 +2707,11 @@ static nsresult ProfileMissingDialog(nsINativeAppSupport* aNative) {
// If aUnlocker is NULL, it is also OK for the following arguments to be NULL:
// aProfileDir, aProfileLocalDir, aResult.
-static ReturnAbortOnError ProfileErrorDialog(nsIFile* aProfileDir,
- nsIFile* aProfileLocalDir,
- ProfileStatus aStatus,
- nsIProfileUnlocker* aUnlocker,
- nsINativeAppSupport* aNative,
- nsIProfileLock** aResult) {
+static ReturnAbortOnError ProfileLockedDialog(nsIFile* aProfileDir,
+ nsIFile* aProfileLocalDir,
+ nsIProfileUnlocker* aUnlocker,
+ nsINativeAppSupport* aNative,
+ nsIProfileLock** aResult) {
nsresult rv;
if (aProfileDir) {
@@ -2821,43 +2745,37 @@ static ReturnAbortOnError ProfileErrorDialog(nsIFile* aProfileDir,
mozilla::components::StringBundle::Service();
NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
+ nsCOMPtr<nsIStringBundle> brandBundle;
+ sbs->CreateBundle(kBrandProperties, getter_AddRefs(brandBundle));
+ NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
nsCOMPtr<nsIStringBundle> sb;
sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
- nsCOMPtr<nsIStringBundle> overrideSB;
- GetOverrideStringBundle(sbs, getter_AddRefs(overrideSB));
+ nsAutoString appName;
+ rv = brandBundle->GetStringFromName("brandShortName", appName);
+ NS_ENSURE_SUCCESS(rv, NS_ERROR_ABORT);
- NS_ConvertUTF8toUTF16 appName(MOZ_APP_DISPLAYNAME);
- AutoTArray<nsString, 3> params = {appName, appName, appName};
+ AutoTArray<nsString, 3> params;
+ params.AppendElement(appName);
+ params.AppendElement(appName);
+ params.AppendElement(appName);
nsAutoString killMessage;
#ifndef XP_MACOSX
- static const char kRestartUnlocker[] = "restartMessageUnlocker";
- static const char kRestartNoUnlocker[] = "restartMessageNoUnlocker2";
- static const char kReadOnly[] = "profileReadOnly";
+ rv = sb->FormatStringFromName(
+ aUnlocker ? "restartMessageUnlocker" : "restartMessageNoUnlocker2",
+ params, killMessage);
#else
- static const char kRestartUnlocker[] = "restartMessageUnlockerMac";
- static const char kRestartNoUnlocker[] = "restartMessageNoUnlockerMac";
- static const char kReadOnly[] = "profileReadOnlyMac";
-#endif
- static const char kAccessDenied[] = "profileAccessDenied";
-
- const char* errorKey = aUnlocker ? kRestartUnlocker : kRestartNoUnlocker;
- if (PROFILE_STATUS_READ_ONLY == aStatus)
- errorKey = kReadOnly;
- else if (PROFILE_STATUS_ACCESS_DENIED == aStatus)
- errorKey = kAccessDenied;
- rv = GetFormattedString(overrideSB, sb, errorKey, params, killMessage);
+ rv = sb->FormatStringFromName(
+ aUnlocker ? "restartMessageUnlockerMac" : "restartMessageNoUnlockerMac",
+ params, killMessage);
+#endif
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
- const char* titleKey = ((PROFILE_STATUS_READ_ONLY == aStatus) ||
- (PROFILE_STATUS_ACCESS_DENIED == aStatus))
- ? "profileProblemTitle"
- : "restartTitle";
params.SetLength(1);
nsAutoString killTitle;
- rv = sb->FormatStringFromName(titleKey, params, killTitle);
+ rv = sb->FormatStringFromName("restartTitle", params, killTitle);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
#ifdef MOZ_BACKGROUNDTASKS
@@ -3028,24 +2946,6 @@ static ReturnAbortOnError ShowProfileManager(
return LaunchChild(false, true);
}
-#ifdef XP_MACOSX
-static ProfileStatus CheckTorBrowserDataWriteAccess() {
- // Check whether we can write to the directory that will contain
- // TorBrowser-Data.
- RefPtr<nsXREDirProvider> singleton = nsXREDirProvider::GetSingleton();
- if (!singleton) {
- return PROFILE_STATUS_OTHER_ERROR;
- }
- nsCOMPtr<nsIFile> tbDataDir;
- nsresult rv = singleton->GetTorBrowserUserDataDir(getter_AddRefs(tbDataDir));
- NS_ENSURE_SUCCESS(rv, PROFILE_STATUS_OTHER_ERROR);
- nsCOMPtr<nsIFile> tbDataDirParent;
- rv = tbDataDir->GetParent(getter_AddRefs(tbDataDirParent));
- NS_ENSURE_SUCCESS(rv, PROFILE_STATUS_OTHER_ERROR);
- return nsToolkitProfileService::CheckProfileWriteAccess(tbDataDirParent);
-}
-#endif
-
static bool gDoMigration = false;
static bool gDoProfileReset = false;
static nsCOMPtr<nsIToolkitProfile> gResetOldProfile;
@@ -3053,13 +2953,6 @@ static nsCOMPtr<nsIToolkitProfile> gResetOldProfile;
static nsresult LockProfile(nsINativeAppSupport* aNative, nsIFile* aRootDir,
nsIFile* aLocalDir, nsIToolkitProfile* aProfile,
nsIProfileLock** aResult) {
- ProfileStatus status =
- (aProfile ? nsToolkitProfileService::CheckProfileWriteAccess(aProfile)
- : nsToolkitProfileService::CheckProfileWriteAccess(aRootDir));
- if (PROFILE_STATUS_OK != status)
- return ProfileErrorDialog(aRootDir, aLocalDir, status, nullptr, aNative,
- aResult);
-
// If you close Firefox and very quickly reopen it, the old Firefox may
// still be closing down. Rather than immediately showing the
// "Firefox is running but is not responding" message, we spend a few
@@ -3086,8 +2979,7 @@ static nsresult LockProfile(nsINativeAppSupport* aNative, nsIFile* aRootDir,
} while (TimeStamp::Now() - start <
TimeDuration::FromSeconds(kLockRetrySeconds));
- return ProfileErrorDialog(aRootDir, aLocalDir, PROFILE_STATUS_IS_LOCKED,
- unlocker, aNative, aResult);
+ return ProfileLockedDialog(aRootDir, aLocalDir, unlocker, aNative, aResult);
}
// Pick a profile. We need to end up with a profile root dir, local dir and
@@ -3102,8 +2994,7 @@ static nsresult LockProfile(nsINativeAppSupport* aNative, nsIFile* aRootDir,
static nsresult SelectProfile(nsToolkitProfileService* aProfileSvc,
nsINativeAppSupport* aNative, nsIFile** aRootDir,
nsIFile** aLocalDir, nsIToolkitProfile** aProfile,
- bool* aWasDefaultSelection,
- nsIProfileLock** aResult) {
+ bool* aWasDefaultSelection) {
StartupTimeline::Record(StartupTimeline::SELECT_PROFILE);
nsresult rv;
@@ -3141,14 +3032,9 @@ static nsresult SelectProfile(nsToolkitProfileService* aProfileSvc,
// Ask the profile manager to select the profile directories to use.
bool didCreate = false;
- ProfileStatus profileStatus = PROFILE_STATUS_OK;
- rv = aProfileSvc->SelectStartupProfile(
- &gArgc, gArgv, gDoProfileReset, aRootDir, aLocalDir, aProfile, &didCreate,
- aWasDefaultSelection, profileStatus);
- if (PROFILE_STATUS_OK != profileStatus) {
- return ProfileErrorDialog(*aRootDir, *aLocalDir, profileStatus, nullptr,
- aNative, aResult);
- }
+ rv = aProfileSvc->SelectStartupProfile(&gArgc, gArgv, gDoProfileReset,
+ aRootDir, aLocalDir, aProfile,
+ &didCreate, aWasDefaultSelection);
if (rv == NS_ERROR_SHOW_PROFILE_MANAGER) {
return ShowProfileManager(aProfileSvc, aNative);
@@ -5062,19 +4948,6 @@ int XREMain::XRE_mainStartup(bool* aExitFlag) {
mProfileSvc = NS_GetToolkitProfileService();
if (!mProfileSvc) {
-#ifdef XP_MACOSX
- // NS_NewToolkitProfileService() returns a generic NS_ERROR_FAILURE error
- // if creation of the TorBrowser-Data directory fails due to access denied
- // or because of a read-only disk volume. Do an extra check here to detect
- // these errors so we can display an informative error message.
- ProfileStatus status = CheckTorBrowserDataWriteAccess();
- if ((PROFILE_STATUS_ACCESS_DENIED == status) ||
- (PROFILE_STATUS_READ_ONLY == status)) {
- ProfileErrorDialog(nullptr, nullptr, status, nullptr, mNativeApp,
- nullptr);
- return 1;
- }
-#endif
// We failed to choose or create profile - notify user and quit
ProfileMissingDialog(mNativeApp);
return 1;
@@ -5084,7 +4957,7 @@ int XREMain::XRE_mainStartup(bool* aExitFlag) {
nsCOMPtr<nsIToolkitProfile> profile;
rv = SelectProfile(mProfileSvc, mNativeApp, getter_AddRefs(mProfD),
getter_AddRefs(mProfLD), getter_AddRefs(profile),
- &wasDefaultSelection, getter_AddRefs(mProfileLock));
+ &wasDefaultSelection);
if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
*aExitFlag = true;
return 0;
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/464b5a…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/464b5a…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser-build][main] Update release prep merge request template
by morgan (@morgan) 30 Oct '24
by morgan (@morgan) 30 Oct '24
30 Oct '24
morgan pushed to branch main at The Tor Project / Applications / tor-browser-build
Commits:
0178b624 by Nicolas Vigier at 2024-10-29T20:08:40+00:00
Update release prep merge request template
Update self-review template to add torbrowser_legacy vars to rbm.conf,
and remove firefox-android.
- - - - -
1 changed file:
- .gitlab/merge_request_templates/relprep.md
Changes:
=====================================
.gitlab/merge_request_templates/relprep.md
=====================================
@@ -10,10 +10,11 @@
- [ ] `var/torbrowser_build`: should be `build1`, unless bumping a previous release preparation
- [ ] `var/browser_release_date`: must not be in the future when we start building
- [ ] `var/torbrowser_incremental_from` (not needed for Android-only releases)
+ - [ ] `var/torbrowser_legacy_version` (For Tor Browser 14.0.x stable releases only)
+ - [ ] `var/torbrowser_legacy_platform_version` (For Tor Browser 14.0.x stable releases only)
- [ ] Tag updates:
- [ ] [Firefox](https://gitlab.torproject.org/tpo/applications/tor-browser/-/tags)
- [ ] Geckoview - should match Firefox
- - [ ] [Firefox Android](https://gitlab.torproject.org/tpo/applications/firefox-android/-/t…
- Tags might be speculative in the release preparation: i.e., they might not exist yet.
- [ ] Addon updates:
- [ ] [NoScript](https://addons.mozilla.org/en-US/firefox/addon/noscript/)
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/0…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/0…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/mullvad-browser][mullvad-browser-128.4.0esr-14.5-1] 2 commits: fixup! Bug 40283: Workaround for the file upload bug
by Pier Angelo Vendrame (@pierov) 29 Oct '24
by Pier Angelo Vendrame (@pierov) 29 Oct '24
29 Oct '24
Pier Angelo Vendrame pushed to branch mullvad-browser-128.4.0esr-14.5-1 at The Tor Project / Applications / Mullvad Browser
Commits:
1eb1dd23 by Pier Angelo Vendrame at 2024-10-29T19:10:13+01:00
fixup! Bug 40283: Workaround for the file upload bug
Lint with android-format.
- - - - -
291acbab by Pier Angelo Vendrame at 2024-10-29T19:10:21+01:00
fixup! Bug 40171: Make WebRequest and GeckoWebExecutor First-Party aware
Lint with android-format.
- - - - -
2 changed files:
- mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
- mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebRequest.java
Changes:
=====================================
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
=====================================
@@ -6301,10 +6301,10 @@ public class GeckoSession {
}
private static String normalizePath(String input) {
- // For an unclear reason, Android media picker delivers file paths
- // starting with double slash. Firefox performs path validation on
- // all paths, and double slash is deemed invalid.
- return input.startsWith("//") ? input.substring(1) : input;
+ // For an unclear reason, Android media picker delivers file paths
+ // starting with double slash. Firefox performs path validation on
+ // all paths, and double slash is deemed invalid.
+ return input.startsWith("//") ? input.substring(1) : input;
}
private static String getFile(final @NonNull Context context, final @NonNull Uri uri) {
=====================================
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebRequest.java
=====================================
@@ -49,9 +49,7 @@ public class WebRequest extends WebMessage {
/** The value of the Referer header for this request. */
public final @Nullable String referrer;
- /**
- * The value of the origin of this request.
- */
+ /** The value of the origin of this request. */
public final @Nullable String origin;
@Retention(RetentionPolicy.SOURCE)
@@ -248,10 +246,10 @@ public class WebRequest extends WebMessage {
* @param origin A URI String
* @return This Builder instance.
*/
- public @NonNull Builder origin(final @Nullable String origin) {
- mOrigin = origin;
- return this;
- }
+ public @NonNull Builder origin(final @Nullable String origin) {
+ mOrigin = origin;
+ return this;
+ }
/**
* @return A {@link WebRequest} constructed with the values from this Builder instance.
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/4e…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/4e…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser][base-browser-128.4.0esr-14.5-1] 2 commits: fixup! Bug 40283: Workaround for the file upload bug
by Pier Angelo Vendrame (@pierov) 29 Oct '24
by Pier Angelo Vendrame (@pierov) 29 Oct '24
29 Oct '24
Pier Angelo Vendrame pushed to branch base-browser-128.4.0esr-14.5-1 at The Tor Project / Applications / Tor Browser
Commits:
4b20df89 by Pier Angelo Vendrame at 2024-10-29T19:08:47+01:00
fixup! Bug 40283: Workaround for the file upload bug
Lint with android-format.
- - - - -
8cd93211 by Pier Angelo Vendrame at 2024-10-29T19:08:54+01:00
fixup! Bug 40171: Make WebRequest and GeckoWebExecutor First-Party aware
Lint with android-format.
- - - - -
2 changed files:
- mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
- mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebRequest.java
Changes:
=====================================
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
=====================================
@@ -6301,10 +6301,10 @@ public class GeckoSession {
}
private static String normalizePath(String input) {
- // For an unclear reason, Android media picker delivers file paths
- // starting with double slash. Firefox performs path validation on
- // all paths, and double slash is deemed invalid.
- return input.startsWith("//") ? input.substring(1) : input;
+ // For an unclear reason, Android media picker delivers file paths
+ // starting with double slash. Firefox performs path validation on
+ // all paths, and double slash is deemed invalid.
+ return input.startsWith("//") ? input.substring(1) : input;
}
private static String getFile(final @NonNull Context context, final @NonNull Uri uri) {
=====================================
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebRequest.java
=====================================
@@ -49,9 +49,7 @@ public class WebRequest extends WebMessage {
/** The value of the Referer header for this request. */
public final @Nullable String referrer;
- /**
- * The value of the origin of this request.
- */
+ /** The value of the origin of this request. */
public final @Nullable String origin;
@Retention(RetentionPolicy.SOURCE)
@@ -248,10 +246,10 @@ public class WebRequest extends WebMessage {
* @param origin A URI String
* @return This Builder instance.
*/
- public @NonNull Builder origin(final @Nullable String origin) {
- mOrigin = origin;
- return this;
- }
+ public @NonNull Builder origin(final @Nullable String origin) {
+ mOrigin = origin;
+ return this;
+ }
/**
* @return A {@link WebRequest} constructed with the values from this Builder instance.
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/3975e7…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/3975e7…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser][tor-browser-128.4.0esr-14.5-1] 6 commits: fixup! Bug 40283: Workaround for the file upload bug
by Pier Angelo Vendrame (@pierov) 29 Oct '24
by Pier Angelo Vendrame (@pierov) 29 Oct '24
29 Oct '24
Pier Angelo Vendrame pushed to branch tor-browser-128.4.0esr-14.5-1 at The Tor Project / Applications / Tor Browser
Commits:
41bcfa1b by Pier Angelo Vendrame at 2024-10-29T19:05:48+01:00
fixup! Bug 40283: Workaround for the file upload bug
Lint with android-format.
- - - - -
c8428799 by Pier Angelo Vendrame at 2024-10-29T19:05:53+01:00
fixup! Bug 40171: Make WebRequest and GeckoWebExecutor First-Party aware
Lint with android-format.
- - - - -
cdcb77db by Pier Angelo Vendrame at 2024-10-29T19:05:53+01:00
fixup! Bug 42247: Android helpers for the TorProvider
Lint with android-format.
- - - - -
ad0782df by Pier Angelo Vendrame at 2024-10-29T19:05:54+01:00
fixup! Bug 40597: Implement TorSettings module
Fix a couple of references to Moat in the generic DomainFrontedRequests
module.
- - - - -
6b2120f9 by Pier Angelo Vendrame at 2024-10-29T19:05:54+01:00
fixup! Bug 40597: Implement TorSettings module
ch.asyncOpen is not a JS async function, so no need to await it.
The async in the name means that the channel will call methods from a
listener object that it takes as an argument when it receives data.
- - - - -
464b5a9b by Pier Angelo Vendrame at 2024-10-29T19:05:55+01:00
fixup! Bug 42247: Android helpers for the TorProvider
Bug 43232: Make the Android Meek transport easier to debug.
- - - - -
8 changed files:
- mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
- mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorIntegrationAndroid.java
- mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorSettings.java
- mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebRequest.java
- mobile/android/geckoview/src/main/java/org/mozilla/geckoview/androidlegacysettings/Prefs.java
- mobile/android/geckoview/src/main/java/org/mozilla/geckoview/androidlegacysettings/TorLegacyAndroidSettings.java
- toolkit/modules/DomainFrontedRequests.sys.mjs
- toolkit/modules/Moat.sys.mjs
Changes:
=====================================
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
=====================================
@@ -6319,10 +6319,10 @@ public class GeckoSession {
}
private static String normalizePath(String input) {
- // For an unclear reason, Android media picker delivers file paths
- // starting with double slash. Firefox performs path validation on
- // all paths, and double slash is deemed invalid.
- return input.startsWith("//") ? input.substring(1) : input;
+ // For an unclear reason, Android media picker delivers file paths
+ // starting with double slash. Firefox performs path validation on
+ // all paths, and double slash is deemed invalid.
+ return input.startsWith("//") ? input.substring(1) : input;
}
private static String getFile(final @NonNull Context context, final @NonNull Uri uri) {
=====================================
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorIntegrationAndroid.java
=====================================
@@ -9,671 +9,720 @@ package org.mozilla.geckoview;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
-
-import androidx.annotation.AnyThread;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.io.InterruptedIOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
-import java.util.Set;
-
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.util.BundleEventListener;
import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.util.GeckoBundle;
-
import org.mozilla.geckoview.androidlegacysettings.TorLegacyAndroidSettings;
public class TorIntegrationAndroid implements BundleEventListener {
- private static final String TAG = "TorIntegrationAndroid";
-
- // Events we listen to
- private static final String EVENT_TOR_START = "GeckoView:Tor:StartTor";
- private static final String EVENT_TOR_STOP = "GeckoView:Tor:StopTor";
- private static final String EVENT_MEEK_START = "GeckoView:Tor:StartMeek";
- private static final String EVENT_MEEK_STOP = "GeckoView:Tor:StopMeek";
- private static final String EVENT_CONNECT_STATE_CHANGED = "GeckoView:Tor:ConnectStateChanged";
- private static final String EVENT_CONNECT_ERROR = "GeckoView:Tor:ConnectError";
- private static final String EVENT_BOOTSTRAP_PROGRESS = "GeckoView:Tor:BootstrapProgress";
- private static final String EVENT_BOOTSTRAP_COMPLETE = "GeckoView:Tor:BootstrapComplete";
- private static final String EVENT_TOR_LOGS = "GeckoView:Tor:Logs";
- private static final String EVENT_SETTINGS_READY = "GeckoView:Tor:SettingsReady";
- private static final String EVENT_SETTINGS_CHANGED = "GeckoView:Tor:SettingsChanged";
- private static final String EVENT_SETTINGS_OPEN = "GeckoView:Tor:OpenSettings";
-
- // Events we emit
- private static final String EVENT_SETTINGS_GET = "GeckoView:Tor:SettingsGet";
- private static final String EVENT_SETTINGS_SET = "GeckoView:Tor:SettingsSet";
- private static final String EVENT_SETTINGS_APPLY = "GeckoView:Tor:SettingsApply";
- private static final String EVENT_SETTINGS_SAVE = "GeckoView:Tor:SettingsSave";
- private static final String EVENT_BOOTSTRAP_BEGIN = "GeckoView:Tor:BootstrapBegin";
- private static final String EVENT_BOOTSTRAP_BEGIN_AUTO = "GeckoView:Tor:BootstrapBeginAuto";
- private static final String EVENT_BOOTSTRAP_CANCEL = "GeckoView:Tor:BootstrapCancel";
- private static final String EVENT_BOOTSTRAP_GET_STATE = "GeckoView:Tor:BootstrapGetState";
-
- private static final String CONTROL_PORT_FILE = "/control-ipc";
- private static final String SOCKS_FILE = "/socks-ipc";
- private static final String COOKIE_AUTH_FILE = "/auth-file";
-
- private final String mLibraryDir;
- private final String mCacheDir;
- private final String mIpcDirectory;
- private final File mDataDir;
-
- private TorProcess mTorProcess = null;
- /**
- * The first time we run a Tor process in this session, we copy some configuration files to be
- * sure we always have the latest version, but if we re-launch a tor process we do not need to
- * copy them again.
- */
- private boolean mCopiedConfigFiles = false;
- /**
- * Allow multiple proxies to be started, even though it might not actually happen.
- * The key should be positive (also 0 is not allowed).
- */
- private final HashMap<Integer, MeekTransport> mMeeks = new HashMap<>();
- private int mMeekCounter;
-
- /**
- * mSettings is a Java-side copy of the authoritative settings in the JS code.
- * It's useful to maintain as the UI may be fetching these options often and we don't watch each
- * fetch to be a passthrough to JS with marshalling/unmarshalling each time.
- */
- private TorSettings mSettings = null;
-
- /* package */ TorIntegrationAndroid(Context context) {
- mLibraryDir = context.getApplicationInfo().nativeLibraryDir;
- mCacheDir = context.getCacheDir().getAbsolutePath();
- mIpcDirectory = mCacheDir + "/tor-private";
- mDataDir = new File(context.getFilesDir(), "tor");
- registerListener();
+ private static final String TAG = "TorIntegrationAndroid";
+
+ // Events we listen to
+ private static final String EVENT_TOR_START = "GeckoView:Tor:StartTor";
+ private static final String EVENT_TOR_STOP = "GeckoView:Tor:StopTor";
+ private static final String EVENT_MEEK_START = "GeckoView:Tor:StartMeek";
+ private static final String EVENT_MEEK_STOP = "GeckoView:Tor:StopMeek";
+ private static final String EVENT_CONNECT_STATE_CHANGED = "GeckoView:Tor:ConnectStateChanged";
+ private static final String EVENT_CONNECT_ERROR = "GeckoView:Tor:ConnectError";
+ private static final String EVENT_BOOTSTRAP_PROGRESS = "GeckoView:Tor:BootstrapProgress";
+ private static final String EVENT_BOOTSTRAP_COMPLETE = "GeckoView:Tor:BootstrapComplete";
+ private static final String EVENT_TOR_LOGS = "GeckoView:Tor:Logs";
+ private static final String EVENT_SETTINGS_READY = "GeckoView:Tor:SettingsReady";
+ private static final String EVENT_SETTINGS_CHANGED = "GeckoView:Tor:SettingsChanged";
+ private static final String EVENT_SETTINGS_OPEN = "GeckoView:Tor:OpenSettings";
+
+ // Events we emit
+ private static final String EVENT_SETTINGS_GET = "GeckoView:Tor:SettingsGet";
+ private static final String EVENT_SETTINGS_SET = "GeckoView:Tor:SettingsSet";
+ private static final String EVENT_SETTINGS_APPLY = "GeckoView:Tor:SettingsApply";
+ private static final String EVENT_SETTINGS_SAVE = "GeckoView:Tor:SettingsSave";
+ private static final String EVENT_BOOTSTRAP_BEGIN = "GeckoView:Tor:BootstrapBegin";
+ private static final String EVENT_BOOTSTRAP_BEGIN_AUTO = "GeckoView:Tor:BootstrapBeginAuto";
+ private static final String EVENT_BOOTSTRAP_CANCEL = "GeckoView:Tor:BootstrapCancel";
+ private static final String EVENT_BOOTSTRAP_GET_STATE = "GeckoView:Tor:BootstrapGetState";
+
+ private static final String CONTROL_PORT_FILE = "/control-ipc";
+ private static final String SOCKS_FILE = "/socks-ipc";
+ private static final String COOKIE_AUTH_FILE = "/auth-file";
+
+ private final String mLibraryDir;
+ private final String mCacheDir;
+ private final String mIpcDirectory;
+ private final File mDataDir;
+
+ private TorProcess mTorProcess = null;
+
+ /**
+ * The first time we run a Tor process in this session, we copy some configuration files to be
+ * sure we always have the latest version, but if we re-launch a tor process we do not need to
+ * copy them again.
+ */
+ private boolean mCopiedConfigFiles = false;
+
+ /**
+ * Allow multiple proxies to be started, even though it might not actually happen. The key should
+ * be positive (also 0 is not allowed).
+ */
+ private final HashMap<Integer, MeekTransport> mMeeks = new HashMap<>();
+
+ private int mMeekCounter;
+
+ /**
+ * mSettings is a Java-side copy of the authoritative settings in the JS code. It's useful to
+ * maintain as the UI may be fetching these options often and we don't watch each fetch to be a
+ * passthrough to JS with marshalling/unmarshalling each time.
+ */
+ private TorSettings mSettings = null;
+
+ /* package */ TorIntegrationAndroid(Context context) {
+ mLibraryDir = context.getApplicationInfo().nativeLibraryDir;
+ mCacheDir = context.getCacheDir().getAbsolutePath();
+ mIpcDirectory = mCacheDir + "/tor-private";
+ mDataDir = new File(context.getFilesDir(), "tor");
+ registerListener();
+ }
+
+ /* package */ synchronized void shutdown() {
+ // FIXME: It seems this never gets called
+ if (mTorProcess != null) {
+ mTorProcess.shutdown();
+ mTorProcess = null;
}
-
- /* package */ synchronized void shutdown() {
- // FIXME: It seems this never gets called
- if (mTorProcess != null) {
- mTorProcess.shutdown();
- mTorProcess = null;
- }
+ }
+
+ private void registerListener() {
+ EventDispatcher.getInstance()
+ .registerUiThreadListener(
+ this,
+ EVENT_TOR_START,
+ EVENT_MEEK_START,
+ EVENT_MEEK_STOP,
+ EVENT_SETTINGS_READY,
+ EVENT_SETTINGS_CHANGED,
+ EVENT_CONNECT_STATE_CHANGED,
+ EVENT_CONNECT_ERROR,
+ EVENT_BOOTSTRAP_PROGRESS,
+ EVENT_BOOTSTRAP_COMPLETE,
+ EVENT_TOR_LOGS,
+ EVENT_SETTINGS_OPEN);
+ }
+
+ @Override // BundleEventListener
+ public synchronized void handleMessage(
+ final String event, final GeckoBundle message, final EventCallback callback) {
+ if (EVENT_TOR_START.equals(event)) {
+ startDaemon(message, callback);
+ } else if (EVENT_TOR_STOP.equals(event)) {
+ stopDaemon(message, callback);
+ } else if (EVENT_MEEK_START.equals(event)) {
+ startMeek(message, callback);
+ } else if (EVENT_MEEK_STOP.equals(event)) {
+ stopMeek(message, callback);
+ } else if (EVENT_SETTINGS_READY.equals(event)) {
+ try {
+ new SettingsLoader().execute(message);
+ } catch (Exception e) {
+ Log.e(TAG, "SettingsLoader error: " + e.toString());
+ }
+ } else if (EVENT_SETTINGS_CHANGED.equals(event)) {
+ GeckoBundle newSettings = message.getBundle("settings");
+ if (newSettings != null) {
+ // TODO: Should we notify listeners?
+ mSettings = new TorSettings(newSettings);
+ } else {
+ Log.w(TAG, "Ignoring a settings changed event that did not have the new settings.");
+ }
+ } else if (EVENT_CONNECT_STATE_CHANGED.equals(event)) {
+ String state = message.getString("state");
+ for (BootstrapStateChangeListener listener : mBootstrapStateListeners) {
+ listener.onBootstrapStateChange(state);
+ }
+ } else if (EVENT_CONNECT_ERROR.equals(event)) {
+ String code = message.getString("code");
+ String msg = message.getString("message");
+ String phase = message.getString("phase");
+ String reason = message.getString("reason");
+ for (BootstrapStateChangeListener listener : mBootstrapStateListeners) {
+ listener.onBootstrapError(code, msg, phase, reason);
+ }
+ } else if (EVENT_BOOTSTRAP_PROGRESS.equals(event)) {
+ double progress = message.getDouble("progress");
+ boolean hasWarnings = message.getBoolean("hasWarnings");
+ for (BootstrapStateChangeListener listener : mBootstrapStateListeners) {
+ listener.onBootstrapProgress(progress, hasWarnings);
+ }
+ } else if (EVENT_BOOTSTRAP_COMPLETE.equals(event)) {
+ for (BootstrapStateChangeListener listener : mBootstrapStateListeners) {
+ listener.onBootstrapComplete();
+ }
+ } else if (EVENT_TOR_LOGS.equals(event)) {
+ String msg = message.getString("message");
+ String type = message.getString("logType");
+ for (TorLogListener listener : mLogListeners) {
+ listener.onLog(type, msg);
+ }
+ } else if (EVENT_SETTINGS_OPEN.equals(event)) {
+ for (BootstrapStateChangeListener listener : mBootstrapStateListeners) {
+ listener.onSettingsRequested();
+ }
}
-
- private void registerListener() {
- EventDispatcher.getInstance()
- .registerUiThreadListener(
- this,
- EVENT_TOR_START,
- EVENT_MEEK_START,
- EVENT_MEEK_STOP,
- EVENT_SETTINGS_READY,
- EVENT_SETTINGS_CHANGED,
- EVENT_CONNECT_STATE_CHANGED,
- EVENT_CONNECT_ERROR,
- EVENT_BOOTSTRAP_PROGRESS,
- EVENT_BOOTSTRAP_COMPLETE,
- EVENT_TOR_LOGS,
- EVENT_SETTINGS_OPEN);
+ }
+
+ private class SettingsLoader extends AsyncTask<GeckoBundle, Void, TorSettings> {
+ protected TorSettings doInBackground(GeckoBundle... messages) {
+ GeckoBundle message = messages[0];
+ TorSettings settings;
+ if (TorLegacyAndroidSettings.unmigrated()) {
+ settings = TorLegacyAndroidSettings.loadTorSettings();
+ } else {
+ GeckoBundle bundle = message.getBundle("settings");
+ settings = new TorSettings(bundle);
+ }
+ return settings;
}
- @Override // BundleEventListener
- public synchronized void handleMessage(
- final String event, final GeckoBundle message, final EventCallback callback) {
- if (EVENT_TOR_START.equals(event)) {
- startDaemon(message, callback);
- } else if (EVENT_TOR_STOP.equals(event)) {
- stopDaemon(message, callback);
- } else if (EVENT_MEEK_START.equals(event)) {
- startMeek(message, callback);
- } else if (EVENT_MEEK_STOP.equals(event)) {
- stopMeek(message, callback);
- } else if (EVENT_SETTINGS_READY.equals(event)) {
- try {
- new SettingsLoader().execute(message);
- } catch(Exception e) {
- Log.e(TAG, "SettingsLoader error: "+ e.toString());
- }
- } else if (EVENT_SETTINGS_CHANGED.equals(event)) {
- GeckoBundle newSettings = message.getBundle("settings");
- if (newSettings != null) {
- // TODO: Should we notify listeners?
- mSettings = new TorSettings(newSettings);
- } else {
- Log.w(TAG, "Ignoring a settings changed event that did not have the new settings.");
- }
- } else if (EVENT_CONNECT_STATE_CHANGED.equals(event)) {
- String state = message.getString("state");
- for (BootstrapStateChangeListener listener: mBootstrapStateListeners) {
- listener.onBootstrapStateChange(state);
- }
- } else if (EVENT_CONNECT_ERROR.equals(event)) {
- String code = message.getString("code");
- String msg = message.getString("message");
- String phase = message.getString("phase");
- String reason = message.getString("reason");
- for (BootstrapStateChangeListener listener: mBootstrapStateListeners) {
- listener.onBootstrapError(code, msg, phase, reason);
- }
- } else if (EVENT_BOOTSTRAP_PROGRESS.equals(event)) {
- double progress = message.getDouble("progress");
- boolean hasWarnings = message.getBoolean("hasWarnings");
- for (BootstrapStateChangeListener listener: mBootstrapStateListeners) {
- listener.onBootstrapProgress(progress, hasWarnings);
- }
- } else if (EVENT_BOOTSTRAP_COMPLETE.equals(event)) {
- for (BootstrapStateChangeListener listener: mBootstrapStateListeners) {
- listener.onBootstrapComplete();
- }
- } else if (EVENT_TOR_LOGS.equals(event)) {
- String msg = message.getString("message");
- String type = message.getString("logType");
- for (TorLogListener listener: mLogListeners) {
- listener.onLog(type, msg);
- }
- } else if (EVENT_SETTINGS_OPEN.equals(event)) {
- for (BootstrapStateChangeListener listener: mBootstrapStateListeners) {
- listener.onSettingsRequested();
- }
- }
+ @Override
+ protected void onPostExecute(TorSettings torSettings) {
+ mSettings = torSettings;
+ if (TorLegacyAndroidSettings.unmigrated()) {
+ setSettings(mSettings, true, true);
+ TorLegacyAndroidSettings.setMigrated();
+ }
+ }
+ }
+
+ private synchronized void startDaemon(final GeckoBundle message, final EventCallback callback) {
+ // Let JS generate this to possibly reduce the chance of race conditions.
+ String handle = message.getString("handle", "");
+ if (handle.isEmpty()) {
+ Log.e(TAG, "Requested to start a tor process without a handle.");
+ callback.sendError("Expected a handle for the new process.");
+ return;
}
+ Log.d(TAG, "Starting the a tor process with handle " + handle);
- private class SettingsLoader extends AsyncTask<GeckoBundle, Void, TorSettings> {
- protected TorSettings doInBackground(GeckoBundle... messages) {
- GeckoBundle message = messages[0];
- TorSettings settings;
- if (TorLegacyAndroidSettings.unmigrated()) {
- settings = TorLegacyAndroidSettings.loadTorSettings();
- } else {
- GeckoBundle bundle = message.getBundle("settings");
- settings = new TorSettings(bundle);
- }
- return settings;
- }
+ TorProcess previousProcess = mTorProcess;
+ if (previousProcess != null) {
+ Log.w(TAG, "We still have a running process: " + previousProcess.getHandle());
+ }
+ mTorProcess = new TorProcess(handle);
+
+ GeckoBundle bundle = new GeckoBundle(3);
+ bundle.putString("controlPortPath", mIpcDirectory + CONTROL_PORT_FILE);
+ bundle.putString("socksPath", mIpcDirectory + SOCKS_FILE);
+ bundle.putString("cookieFilePath", mIpcDirectory + COOKIE_AUTH_FILE);
+ callback.sendSuccess(bundle);
+ }
+
+ private synchronized void stopDaemon(final GeckoBundle message, final EventCallback callback) {
+ if (mTorProcess == null) {
+ if (callback != null) {
+ callback.sendSuccess(null);
+ }
+ return;
+ }
+ String handle = message.getString("handle", "");
+ if (!mTorProcess.getHandle().equals(handle)) {
+ GeckoBundle bundle = new GeckoBundle(1);
+ bundle.putString(
+ "error", "The requested process has not been found. It might have already been stopped.");
+ callback.sendError(bundle);
+ return;
+ }
+ mTorProcess.shutdown();
+ mTorProcess = null;
+ callback.sendSuccess(null);
+ }
+
+ class TorProcess extends Thread {
+ private static final String EVENT_TOR_STARTED = "GeckoView:Tor:TorStarted";
+ private static final String EVENT_TOR_START_FAILED = "GeckoView:Tor:TorStartFailed";
+ private static final String EVENT_TOR_EXITED = "GeckoView:Tor:TorExited";
+ private final String mHandle;
+ private Process mProcess = null;
+
+ TorProcess(String handle) {
+ mHandle = handle;
+ setName("tor-process-" + handle);
+ start();
+ }
- @Override
- protected void onPostExecute(TorSettings torSettings) {
- mSettings = torSettings;
- if (TorLegacyAndroidSettings.unmigrated()) {
- setSettings(mSettings, true, true);
- TorLegacyAndroidSettings.setMigrated();
- }
+ @Override
+ public void run() {
+ cleanIpcDirectory();
+
+ final String ipcDir = TorIntegrationAndroid.this.mIpcDirectory;
+ final ArrayList<String> args = new ArrayList<>();
+ args.add(mLibraryDir + "/libTor.so");
+ args.add("DisableNetwork");
+ args.add("1");
+ args.add("+__ControlPort");
+ args.add("unix:" + ipcDir + CONTROL_PORT_FILE);
+ args.add("+__SocksPort");
+ args.add("unix:" + ipcDir + SOCKS_FILE + " IPv6Traffic PreferIPv6 KeepAliveIsolateSOCKSAuth");
+ args.add("CookieAuthentication");
+ args.add("1");
+ args.add("CookieAuthFile");
+ args.add(ipcDir + COOKIE_AUTH_FILE);
+ args.add("DataDirectory");
+ args.add(mDataDir.getAbsolutePath());
+ boolean copied = true;
+ try {
+ copyAndUseConfigFile("--defaults-torrc", "torrc-defaults", args);
+ } catch (IOException e) {
+ Log.w(
+ TAG, "torrc-default cannot be created, pluggable transports will not be available", e);
+ copied = false;
+ }
+ // tor-browser#42607: For now we do not ship geoip databases, as we
+ // do not have the circuit display functionality and they allow us
+ // to save some space in the final APK.
+ /*try {
+ copyAndUseConfigFile("GeoIPFile", "geoip", args);
+ copyAndUseConfigFile("GeoIPv6File", "geoip6", args);
+ } catch (IOException e) {
+ Log.w(TAG, "GeoIP files cannot be created, this feature will not be available.", e);
+ copied = false;
+ }*/
+ mCopiedConfigFiles = copied;
+
+ Log.d(TAG, "Starting tor with the follwing args: " + args.toString());
+ final ProcessBuilder builder = new ProcessBuilder(args);
+ builder.directory(new File(mLibraryDir));
+ try {
+ mProcess = builder.start();
+ } catch (IOException e) {
+ Log.e(TAG, "Cannot start tor " + mHandle, e);
+ final GeckoBundle data = new GeckoBundle(2);
+ data.putString("handle", mHandle);
+ data.putString("error", e.getMessage());
+ EventDispatcher.getInstance().dispatch(EVENT_TOR_START_FAILED, data);
+ return;
+ }
+ Log.i(TAG, "Tor process " + mHandle + " started.");
+ {
+ final GeckoBundle data = new GeckoBundle(1);
+ data.putString("handle", mHandle);
+ EventDispatcher.getInstance().dispatch(EVENT_TOR_STARTED, data);
+ }
+ try {
+ BufferedReader reader =
+ new BufferedReader(new InputStreamReader(mProcess.getInputStream()));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ Log.i(TAG, "[tor-" + mHandle + "] " + line);
}
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to read stdout of the tor process " + mHandle, e);
+ }
+ Log.d(TAG, "Exiting the stdout loop for process " + mHandle);
+ final GeckoBundle data = new GeckoBundle(2);
+ data.putString("handle", mHandle);
+ try {
+ data.putInt("status", mProcess.waitFor());
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Failed to wait for the tor process " + mHandle, e);
+ data.putInt("status", 0xdeadbeef);
+ }
+ // FIXME: We usually don't reach this when the application is killed!
+ // So, we don't do our cleanup.
+ Log.i(TAG, "Tor process " + mHandle + " has exited.");
+ EventDispatcher.getInstance().dispatch(EVENT_TOR_EXITED, data);
}
- private synchronized void startDaemon(final GeckoBundle message, final EventCallback callback) {
- // Let JS generate this to possibly reduce the chance of race conditions.
- String handle = message.getString("handle", "");
- if (handle.isEmpty()) {
- Log.e(TAG, "Requested to start a tor process without a handle.");
- callback.sendError("Expected a handle for the new process.");
- return;
+ private void cleanIpcDirectory() {
+ File directory = new File(TorIntegrationAndroid.this.mIpcDirectory);
+ if (!directory.isDirectory()) {
+ if (!directory.mkdirs()) {
+ Log.e(TAG, "Failed to create the IPC directory.");
+ return;
}
- Log.d(TAG, "Starting the a tor process with handle " + handle);
-
- TorProcess previousProcess = mTorProcess;
- if (previousProcess != null) {
- Log.w(TAG, "We still have a running process: " + previousProcess.getHandle());
+ try {
+ // First remove the permissions for everybody...
+ directory.setReadable(false, false);
+ directory.setWritable(false, false);
+ directory.setExecutable(false, false);
+ // ... then add them back, but only for the owner.
+ directory.setReadable(true, true);
+ directory.setWritable(true, true);
+ directory.setExecutable(true, true);
+ } catch (SecurityException e) {
+ Log.e(TAG, "Could not set the permissions to the IPC directory.", e);
}
- mTorProcess = new TorProcess(handle);
+ return;
+ }
+ // We assume we do not have child directories, only files
+ File[] maybeFiles = directory.listFiles();
+ if (maybeFiles != null) {
+ for (File file : maybeFiles) {
+ if (!file.delete()) {
+ Log.d(TAG, "Could not delete " + file);
+ }
+ }
+ }
+ }
- GeckoBundle bundle = new GeckoBundle(3);
- bundle.putString("controlPortPath", mIpcDirectory + CONTROL_PORT_FILE);
- bundle.putString("socksPath", mIpcDirectory + SOCKS_FILE);
- bundle.putString("cookieFilePath", mIpcDirectory + COOKIE_AUTH_FILE);
- callback.sendSuccess(bundle);
+ private void copyAndUseConfigFile(String option, String name, ArrayList<String> args)
+ throws IOException {
+ File file = copyConfigFile(name);
+ args.add(option);
+ args.add(file.getAbsolutePath());
}
- private synchronized void stopDaemon(final GeckoBundle message, final EventCallback callback) {
- if (mTorProcess == null) {
- if (callback != null) {
- callback.sendSuccess(null);
- }
- return;
+ private File copyConfigFile(String name) throws IOException {
+ final File file = new File(mCacheDir, name);
+ if (mCopiedConfigFiles && file.exists()) {
+ return file;
+ }
+
+ final Context context = GeckoAppShell.getApplicationContext();
+ final InputStream in = context.getAssets().open("common/" + name);
+ // Files.copy is API 26+, so use java.io and a loop for now.
+ FileOutputStream out = null;
+ try {
+ out = new FileOutputStream(file);
+ } catch (IOException e) {
+ in.close();
+ throw e;
+ }
+ try {
+ byte buffer[] = new byte[4096];
+ int read;
+ while ((read = in.read(buffer)) >= 0) {
+ out.write(buffer, 0, read);
}
- String handle = message.getString("handle", "");
- if (!mTorProcess.getHandle().equals(handle)) {
- GeckoBundle bundle = new GeckoBundle(1);
- bundle.putString("error", "The requested process has not been found. It might have already been stopped.");
- callback.sendError(bundle);
- return;
+ } finally {
+ try {
+ in.close();
+ } catch (IOException e) {
+ Log.w(TAG, "Cannot close the input stream for " + name);
}
- mTorProcess.shutdown();
- mTorProcess = null;
- callback.sendSuccess(null);
+ try {
+ out.close();
+ } catch (IOException e) {
+ Log.w(TAG, "Cannot close the output stream for " + name);
+ }
+ }
+ return file;
}
- class TorProcess extends Thread {
- private static final String EVENT_TOR_STARTED = "GeckoView:Tor:TorStarted";
- private static final String EVENT_TOR_START_FAILED = "GeckoView:Tor:TorStartFailed";
- private static final String EVENT_TOR_EXITED = "GeckoView:Tor:TorExited";
- private final String mHandle;
- private Process mProcess = null;
-
- TorProcess(String handle) {
- mHandle = handle;
- setName("tor-process-" + handle);
- start();
+ public void shutdown() {
+ if (mProcess != null && mProcess.isAlive()) {
+ mProcess.destroy();
+ }
+ if (isAlive()) {
+ try {
+ join();
+ } catch (InterruptedException e) {
+ Log.e(
+ TAG,
+ "Cannot join the thread for tor process " + mHandle + ", possibly already terminated",
+ e);
}
+ }
+ }
- @Override
- public void run() {
- cleanIpcDirectory();
-
- final String ipcDir = TorIntegrationAndroid.this.mIpcDirectory;
- final ArrayList<String> args = new ArrayList<>();
- args.add(mLibraryDir + "/libTor.so");
- args.add("DisableNetwork");
- args.add("1");
- args.add("+__ControlPort");
- args.add("unix:" + ipcDir + CONTROL_PORT_FILE);
- args.add("+__SocksPort");
- args.add("unix:" + ipcDir + SOCKS_FILE + " IPv6Traffic PreferIPv6 KeepAliveIsolateSOCKSAuth");
- args.add("CookieAuthentication");
- args.add("1");
- args.add("CookieAuthFile");
- args.add(ipcDir + COOKIE_AUTH_FILE);
- args.add("DataDirectory");
- args.add(mDataDir.getAbsolutePath());
- boolean copied = true;
- try {
- copyAndUseConfigFile("--defaults-torrc", "torrc-defaults", args);
- } catch (IOException e) {
- Log.w(TAG, "torrc-default cannot be created, pluggable transports will not be available", e);
- copied = false;
- }
- // tor-browser#42607: For now we do not ship geoip databases, as we
- // do not have the circuit display functionality and they allow us
- // to save some space in the final APK.
- /*try {
- copyAndUseConfigFile("GeoIPFile", "geoip", args);
- copyAndUseConfigFile("GeoIPv6File", "geoip6", args);
- } catch (IOException e) {
- Log.w(TAG, "GeoIP files cannot be created, this feature will not be available.", e);
- copied = false;
- }*/
- mCopiedConfigFiles = copied;
-
- Log.d(TAG, "Starting tor with the follwing args: " + args.toString());
- final ProcessBuilder builder = new ProcessBuilder(args);
- builder.directory(new File(mLibraryDir));
- try {
- mProcess = builder.start();
- } catch (IOException e) {
- Log.e(TAG, "Cannot start tor " + mHandle, e);
- final GeckoBundle data = new GeckoBundle(2);
- data.putString("handle", mHandle);
- data.putString("error", e.getMessage());
- EventDispatcher.getInstance().dispatch(EVENT_TOR_START_FAILED, data);
- return;
- }
- Log.i(TAG, "Tor process " + mHandle + " started.");
- {
- final GeckoBundle data = new GeckoBundle(1);
- data.putString("handle", mHandle);
- EventDispatcher.getInstance().dispatch(EVENT_TOR_STARTED, data);
- }
- try {
- BufferedReader reader = new BufferedReader(new InputStreamReader(mProcess.getInputStream()));
- String line;
- while ((line = reader.readLine()) != null) {
- Log.i(TAG, "[tor-" + mHandle + "] " + line);
- }
- } catch (IOException e) {
- Log.e(TAG, "Failed to read stdout of the tor process " + mHandle, e);
- }
- Log.d(TAG, "Exiting the stdout loop for process " + mHandle);
- final GeckoBundle data = new GeckoBundle(2);
- data.putString("handle", mHandle);
- try {
- data.putInt("status", mProcess.waitFor());
- } catch (InterruptedException e) {
- Log.e(TAG, "Failed to wait for the tor process " + mHandle, e);
- data.putInt("status", 0xdeadbeef);
- }
- // FIXME: We usually don't reach this when the application is killed!
- // So, we don't do our cleanup.
- Log.i(TAG, "Tor process " + mHandle + " has exited.");
- EventDispatcher.getInstance().dispatch(EVENT_TOR_EXITED, data);
- }
+ public String getHandle() {
+ return mHandle;
+ }
+ }
+
+ private synchronized void startMeek(final GeckoBundle message, final EventCallback callback) {
+ if (callback == null) {
+ Log.e(TAG, "Tried to start Meek without a callback.");
+ return;
+ }
+ mMeekCounter++;
+ mMeeks.put(
+ new Integer(mMeekCounter),
+ new MeekTransport(callback, mMeekCounter, message.getStringArray("arguments")));
+ }
+
+ private synchronized void stopMeek(final GeckoBundle message, final EventCallback callback) {
+ final Integer key = message.getInteger("id");
+ final MeekTransport meek = mMeeks.remove(key);
+ if (meek != null) {
+ meek.shutdown();
+ }
+ if (callback != null) {
+ callback.sendSuccess(null);
+ }
+ }
+
+ private class MeekTransport extends Thread {
+ private static final String TRANSPORT = "meek_lite";
+ private Process mProcess;
+ private final EventCallback mCallback;
+ private final int mId;
+
+ MeekTransport(final EventCallback callback, int id, String[] args) {
+ setName("meek-" + id);
+
+ final String command = mLibraryDir + "/libObfs4proxy.so";
+ ArrayList<String> argList = new ArrayList<String>();
+ argList.add(command);
+ if (args != null && args.length > 0) {
+ // Normally not used, but it helps to debug only by editing JS.
+ Log.d(TAG, "Requested custom arguments for meek: " + String.join(" ", args));
+ argList.addAll(Arrays.asList(args));
+ }
+ final ProcessBuilder builder = new ProcessBuilder(argList);
+
+ File ptStateDir = new File(mDataDir, "pt_state");
+ Log.d(TAG, "Using " + ptStateDir.getAbsolutePath() + " as a state directory for meek.");
+ final Map<String, String> env = builder.environment();
+ env.put("TOR_PT_MANAGED_TRANSPORT_VER", "1");
+ env.put("TOR_PT_STATE_LOCATION", ptStateDir.getAbsolutePath());
+ env.put("TOR_PT_EXIT_ON_STDIN_CLOSE", "1");
+ env.put("TOR_PT_CLIENT_TRANSPORTS", TRANSPORT);
+
+ mCallback = callback;
+ mId = id;
+ try {
+ // We expect this process to be short-lived, therefore we do not bother with
+ // implementing this as a service.
+ mProcess = builder.start();
+ } catch (IOException e) {
+ Log.e(TAG, "Cannot start the PT", e);
+ callback.sendError(e.getMessage());
+ return;
+ }
+ start();
+ }
- private void cleanIpcDirectory() {
- File directory = new File(TorIntegrationAndroid.this.mIpcDirectory);
- if (!directory.isDirectory()) {
- if (!directory.mkdirs()) {
- Log.e(TAG, "Failed to create the IPC directory.");
- return;
- }
- try {
- // First remove the permissions for everybody...
- directory.setReadable(false, false);
- directory.setWritable(false, false);
- directory.setExecutable(false, false);
- // ... then add them back, but only for the owner.
- directory.setReadable(true, true);
- directory.setWritable(true, true);
- directory.setExecutable(true, true);
- } catch (SecurityException e) {
- Log.e(TAG, "Could not set the permissions to the IPC directory.", e);
- }
- return;
+ /**
+ * Parse the standard output of the pluggable transport to find the hostname and port it is
+ * listening on.
+ *
+ * <p>See also the specs for the IPC protocol at https://spec.torproject.org/pt-spec/ipc.html.
+ */
+ @Override
+ public void run() {
+ final String PROTOCOL_VERSION = "1";
+ String hostname = "";
+ boolean valid = false;
+ int port = 0;
+ String error = "Did not see a CMETHOD";
+ try {
+ InputStreamReader isr = new InputStreamReader(mProcess.getInputStream());
+ BufferedReader reader = new BufferedReader(isr);
+ String line;
+ while ((line = reader.readLine()) != null) {
+ line = line.trim();
+ Log.d(TAG, "Meek line: " + line);
+ // Split produces always at least one item
+ String[] tokens = line.split(" ");
+ if ("VERSION".equals(tokens[0])
+ && (tokens.length != 2 || !PROTOCOL_VERSION.equals(tokens[1]))) {
+ error = "Bad version: " + line;
+ break;
+ }
+ if ("CMETHOD".equals(tokens[0])) {
+ if (tokens.length != 4) {
+ error = "Bad number of tokens in CMETHOD: " + line;
+ break;
}
- // We assume we do not have child directories, only files
- File[] maybeFiles = directory.listFiles();
- if (maybeFiles != null) {
- for (File file : maybeFiles) {
- if (!file.delete()) {
- Log.d(TAG, "Could not delete " + file);
- }
- }
+ if (!tokens[1].equals(TRANSPORT)) {
+ error = "Unexpected transport: " + tokens[1];
+ break;
}
- }
-
- private void copyAndUseConfigFile(String option, String name, ArrayList<String> args) throws IOException {
- File file = copyConfigFile(name);
- args.add(option);
- args.add(file.getAbsolutePath());
- }
-
- private File copyConfigFile(String name) throws IOException {
- final File file = new File(mCacheDir, name);
- if (mCopiedConfigFiles && file.exists()) {
- return file;
+ if (!"socks5".equals(tokens[2])) {
+ error = "Unexpected proxy type: " + tokens[2];
+ break;
}
-
- final Context context = GeckoAppShell.getApplicationContext();
- final InputStream in = context.getAssets().open("common/" + name);
- // Files.copy is API 26+, so use java.io and a loop for now.
- FileOutputStream out = null;
- try {
- out = new FileOutputStream(file);
- } catch (IOException e) {
- in.close();
- throw e;
+ String[] addr = tokens[3].split(":");
+ if (addr.length != 2) {
+ error = "Invalid address";
+ break;
}
+ hostname = addr[0];
try {
- byte buffer[] = new byte[4096];
- int read;
- while ((read = in.read(buffer)) >= 0) {
- out.write(buffer, 0, read);
- }
- } finally {
- try {
- in.close();
- } catch (IOException e) {
- Log.w(TAG, "Cannot close the input stream for " + name);
- }
- try {
- out.close();
- } catch (IOException e) {
- Log.w(TAG, "Cannot close the output stream for " + name);
- }
- }
- return file;
- }
-
- public void shutdown() {
- if (mProcess != null && mProcess.isAlive()) {
- mProcess.destroy();
+ port = Integer.parseInt(addr[1]);
+ } catch (NumberFormatException e) {
+ error = "Invalid port: " + e.getMessage();
+ break;
}
- if (isAlive()) {
- try {
- join();
- } catch (InterruptedException e) {
- Log.e(TAG, "Cannot join the thread for tor process " + mHandle + ", possibly already terminated", e);
- }
+ if (port < 1 || port > 65535) {
+ error = "Invalid port: out of bounds";
+ break;
}
+ valid = true;
+ break;
+ }
+ if (tokens[0].endsWith("-ERROR")) {
+ error = "Seen an error: " + line;
+ break;
+ }
}
-
- public String getHandle() {
- return mHandle;
- }
+ } catch (Exception e) {
+ error = e.getMessage();
+ }
+ if (valid) {
+ Log.d(TAG, "Setup a meek transport " + mId + ": " + hostname + ":" + port);
+ final GeckoBundle bundle = new GeckoBundle(3);
+ bundle.putInt("id", mId);
+ bundle.putString("address", hostname);
+ bundle.putInt("port", port);
+ mCallback.sendSuccess(bundle);
+ } else {
+ Log.e(TAG, "Failed to get a usable config from the PT: " + error);
+ mCallback.sendError(error);
+ return;
+ }
+ dumpStdout();
}
- private synchronized void startMeek(final GeckoBundle message, final EventCallback callback) {
- if (callback == null) {
- Log.e(TAG, "Tried to start Meek without a callback.");
- return;
- }
- mMeekCounter++;
- mMeeks.put(new Integer(mMeekCounter), new MeekTransport(callback, mMeekCounter));
+ void shutdown() {
+ if (mProcess != null) {
+ Log.i(TAG, "Shutting down meek process " + mId);
+ mProcess.destroy();
+ mProcess = null;
+ } else {
+ Log.w(
+ TAG,
+ "Shutdown request on the meek process " + mId + " that has already been shutdown.");
+ }
+ try {
+ join();
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Could not join the meek thread", e);
+ }
}
- private synchronized void stopMeek(final GeckoBundle message, final EventCallback callback) {
- final Integer key = message.getInteger("id");
- final MeekTransport meek = mMeeks.remove(key);
- if (meek != null) {
- meek.shutdown();
- }
- if (callback != null) {
- callback.sendSuccess(null);
+ void dumpStdout() {
+ try {
+ BufferedReader reader =
+ new BufferedReader(new InputStreamReader(mProcess.getInputStream()));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ Log.d(TAG, "[meek-" + mId + "] " + line);
}
+ } catch (InterruptedIOException e) {
+ // This happens normally, do not log it.
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to read stdout of the meek process process " + mId, e);
+ }
}
+ }
- private class MeekTransport extends Thread {
- private static final String TRANSPORT = "meek_lite";
- private Process mProcess;
- private final EventCallback mCallback;
- private final int mId;
-
- MeekTransport(final EventCallback callback, int id) {
- setName("meek-" + id);
- final ProcessBuilder builder = new ProcessBuilder(mLibraryDir + "/libObfs4proxy.so");
- {
- File ptStateDir = new File(mDataDir, "pt_state");
- final Map<String, String> env = builder.environment();
- env.put("TOR_PT_MANAGED_TRANSPORT_VER", "1");
- env.put("TOR_PT_STATE_LOCATION", ptStateDir.getAbsolutePath());
- env.put("TOR_PT_EXIT_ON_STDIN_CLOSE", "1");
- env.put("TOR_PT_CLIENT_TRANSPORTS", TRANSPORT);
- }
- mCallback = callback;
- mId = id;
- try {
- // We expect this process to be short-lived, therefore we do not bother with
- // implementing this as a service.
- mProcess = builder.start();
- } catch (IOException e) {
- Log.e(TAG, "Cannot start the PT", e);
- callback.sendError(e.getMessage());
- return;
- }
- start();
- }
+ public interface BootstrapStateChangeListener {
+ void onBootstrapStateChange(String state);
- /**
- * Parse the standard output of the pluggable transport to find the hostname and port it is
- * listening on.
- * <p>
- * See also the specs for the IPC protocol at https://spec.torproject.org/pt-spec/ipc.html.
- */
- @Override
- public void run() {
- final String PROTOCOL_VERSION = "1";
- String hostname = "";
- boolean valid = false;
- int port = 0;
- String error = "Did not see a CMETHOD";
- try {
- InputStreamReader isr = new InputStreamReader(mProcess.getInputStream());
- BufferedReader reader = new BufferedReader(isr);
- String line;
- while ((line = reader.readLine()) != null) {
- line = line.trim();
- Log.d(TAG, "Meek line: " + line);
- // Split produces always at least one item
- String[] tokens = line.split(" ");
- if ("VERSION".equals(tokens[0]) && (tokens.length != 2 || !PROTOCOL_VERSION.equals(tokens[1]))) {
- error = "Bad version: " + line;
- break;
- }
- if ("CMETHOD".equals(tokens[0])) {
- if (tokens.length != 4) {
- error = "Bad number of tokens in CMETHOD: " + line;
- break;
- }
- if (!tokens[1].equals(TRANSPORT)) {
- error = "Unexpected transport: " + tokens[1];
- break;
- }
- if (!"socks5".equals(tokens[2])) {
- error = "Unexpected proxy type: " + tokens[2];
- break;
- }
- String[] addr = tokens[3].split(":");
- if (addr.length != 2) {
- error = "Invalid address";
- break;
- }
- hostname = addr[0];
- try {
- port = Integer.parseInt(addr[1]);
- } catch (NumberFormatException e) {
- error = "Invalid port: " + e.getMessage();
- break;
- }
- if (port < 1 || port > 65535) {
- error = "Invalid port: out of bounds";
- break;
- }
- valid = true;
- break;
- }
- if (tokens[0].endsWith("-ERROR")) {
- error = "Seen an error: " + line;
- break;
- }
- }
- } catch (Exception e) {
- error = e.getMessage();
- }
- if (valid) {
- Log.d(TAG, "Setup a meek transport " + mId + ": " + hostname + ":" + port);
- final GeckoBundle bundle = new GeckoBundle(3);
- bundle.putInt("id", mId);
- bundle.putString("address", hostname);
- bundle.putInt("port", port);
- mCallback.sendSuccess(bundle);
- } else {
- Log.e(TAG, "Failed to get a usable config from the PT: " + error);
- mCallback.sendError(error);
- }
- }
+ void onBootstrapProgress(double progress, boolean hasWarnings);
- void shutdown() {
- if (mProcess != null) {
- mProcess.destroy();
- mProcess = null;
- }
- try {
- join();
- } catch (InterruptedException e) {
- Log.e(TAG, "Could not join the meek thread", e);
- }
- }
- }
+ void onBootstrapComplete();
- public interface BootstrapStateChangeListener {
- void onBootstrapStateChange(String state);
- void onBootstrapProgress(double progress, boolean hasWarnings);
- void onBootstrapComplete();
- void onBootstrapError(String code, String message, String phase, String reason);
- void onSettingsRequested();
- }
+ void onBootstrapError(String code, String message, String phase, String reason);
- public interface TorLogListener {
- void onLog(String logType, String message);
- }
+ void onSettingsRequested();
+ }
- private @NonNull void reloadSettings() {
- EventDispatcher.getInstance().queryBundle(EVENT_SETTINGS_GET).then( new GeckoResult.OnValueListener<GeckoBundle, Void>() {
- public GeckoResult<Void> onValue(final GeckoBundle bundle) {
+ public interface TorLogListener {
+ void onLog(String logType, String message);
+ }
+
+ private @NonNull void reloadSettings() {
+ EventDispatcher.getInstance()
+ .queryBundle(EVENT_SETTINGS_GET)
+ .then(
+ new GeckoResult.OnValueListener<GeckoBundle, Void>() {
+ public GeckoResult<Void> onValue(final GeckoBundle bundle) {
mSettings = new TorSettings(bundle);
return new GeckoResult<Void>();
- }
- });
- }
+ }
+ });
+ }
- public TorSettings getSettings() {
- return mSettings;
- }
+ public TorSettings getSettings() {
+ return mSettings;
+ }
- public void setSettings(final TorSettings settings, boolean save, boolean apply) {
- mSettings = settings;
+ public void setSettings(final TorSettings settings, boolean save, boolean apply) {
+ mSettings = settings;
- emitSetSettings(settings, save, apply).then(
+ emitSetSettings(settings, save, apply)
+ .then(
new GeckoResult.OnValueListener<Void, Void>() {
- public GeckoResult<Void> onValue(Void v) {
- return new GeckoResult<Void>();
- }
+ public GeckoResult<Void> onValue(Void v) {
+ return new GeckoResult<Void>();
+ }
},
new GeckoResult.OnExceptionListener<Void>() {
- public GeckoResult<Void> onException(final Throwable e) {
- Log.e(TAG, "Failed to set settings", e);
- reloadSettings();
- return new GeckoResult<Void>();
- }
+ public GeckoResult<Void> onException(final Throwable e) {
+ Log.e(TAG, "Failed to set settings", e);
+ reloadSettings();
+ return new GeckoResult<Void>();
+ }
});
- }
-
- private @NonNull GeckoResult<Void> emitSetSettings(final TorSettings settings, boolean save, boolean apply) {
- GeckoBundle bundle = new GeckoBundle(3);
- bundle.putBoolean("save", save);
- bundle.putBoolean("apply", apply);
- bundle.putBundle("settings", settings.asGeckoBundle());
- return EventDispatcher.getInstance().queryVoid(EVENT_SETTINGS_SET, bundle);
- }
-
- public @NonNull GeckoResult<Void> applySettings() {
- return EventDispatcher.getInstance().queryVoid(EVENT_SETTINGS_APPLY);
- }
-
- public @NonNull GeckoResult<Void> saveSettings() {
- return EventDispatcher.getInstance().queryVoid(EVENT_SETTINGS_SAVE);
- }
-
- public @NonNull GeckoResult<Void> beginBootstrap() {
- return EventDispatcher.getInstance().queryVoid(EVENT_BOOTSTRAP_BEGIN);
- }
-
- public @NonNull GeckoResult<Void> beginAutoBootstrap(final String countryCode) {
- final GeckoBundle bundle = new GeckoBundle(1);
- bundle.putString("countryCode", countryCode);
- return EventDispatcher.getInstance().queryVoid(EVENT_BOOTSTRAP_BEGIN_AUTO, bundle);
- }
-
- public @NonNull GeckoResult<Void> beginAutoBootstrap() {
- return beginAutoBootstrap(null);
- }
-
- public @NonNull GeckoResult<Void> cancelBootstrap() {
- return EventDispatcher.getInstance().queryVoid(EVENT_BOOTSTRAP_CANCEL);
- }
-
- public void registerBootstrapStateChangeListener(BootstrapStateChangeListener listener) {
- mBootstrapStateListeners.add(listener);
- }
-
- public void unregisterBootstrapStateChangeListener(BootstrapStateChangeListener listener) {
- mBootstrapStateListeners.remove(listener);
- }
-
- private final HashSet<BootstrapStateChangeListener> mBootstrapStateListeners = new HashSet<>();
-
- public void registerLogListener(TorLogListener listener) {
- mLogListeners.add(listener);
- }
-
- public void unregisterLogListener(TorLogListener listener) {
- mLogListeners.remove(listener);
- }
-
- private final HashSet<TorLogListener> mLogListeners = new HashSet<>();
+ }
+
+ private @NonNull GeckoResult<Void> emitSetSettings(
+ final TorSettings settings, boolean save, boolean apply) {
+ GeckoBundle bundle = new GeckoBundle(3);
+ bundle.putBoolean("save", save);
+ bundle.putBoolean("apply", apply);
+ bundle.putBundle("settings", settings.asGeckoBundle());
+ return EventDispatcher.getInstance().queryVoid(EVENT_SETTINGS_SET, bundle);
+ }
+
+ public @NonNull GeckoResult<Void> applySettings() {
+ return EventDispatcher.getInstance().queryVoid(EVENT_SETTINGS_APPLY);
+ }
+
+ public @NonNull GeckoResult<Void> saveSettings() {
+ return EventDispatcher.getInstance().queryVoid(EVENT_SETTINGS_SAVE);
+ }
+
+ public @NonNull GeckoResult<Void> beginBootstrap() {
+ return EventDispatcher.getInstance().queryVoid(EVENT_BOOTSTRAP_BEGIN);
+ }
+
+ public @NonNull GeckoResult<Void> beginAutoBootstrap(final String countryCode) {
+ final GeckoBundle bundle = new GeckoBundle(1);
+ bundle.putString("countryCode", countryCode);
+ return EventDispatcher.getInstance().queryVoid(EVENT_BOOTSTRAP_BEGIN_AUTO, bundle);
+ }
+
+ public @NonNull GeckoResult<Void> beginAutoBootstrap() {
+ return beginAutoBootstrap(null);
+ }
+
+ public @NonNull GeckoResult<Void> cancelBootstrap() {
+ return EventDispatcher.getInstance().queryVoid(EVENT_BOOTSTRAP_CANCEL);
+ }
+
+ public void registerBootstrapStateChangeListener(BootstrapStateChangeListener listener) {
+ mBootstrapStateListeners.add(listener);
+ }
+
+ public void unregisterBootstrapStateChangeListener(BootstrapStateChangeListener listener) {
+ mBootstrapStateListeners.remove(listener);
+ }
+
+ private final HashSet<BootstrapStateChangeListener> mBootstrapStateListeners = new HashSet<>();
+
+ public void registerLogListener(TorLogListener listener) {
+ mLogListeners.add(listener);
+ }
+
+ public void unregisterLogListener(TorLogListener listener) {
+ mLogListeners.remove(listener);
+ }
+
+ private final HashSet<TorLogListener> mLogListeners = new HashSet<>();
}
=====================================
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorSettings.java
=====================================
@@ -1,185 +1,192 @@
package org.mozilla.geckoview;
import android.util.Log;
-
import org.mozilla.gecko.util.GeckoBundle;
public class TorSettings {
- public enum BridgeSource {
- Invalid(-1),
- BuiltIn(0),
- BridgeDB(1),
- UserProvided(2);
-
- private int source;
-
- BridgeSource(final int source) {
- this.source = source;
- }
-
- public static BridgeSource fromInt(int i) {
- switch (i) {
- case -1: return Invalid;
- case 0: return BuiltIn;
- case 1: return BridgeDB;
- case 2: return UserProvided;
- }
- return Invalid;
- }
-
- public int toInt() {
- return this.source;
- }
+ public enum BridgeSource {
+ Invalid(-1),
+ BuiltIn(0),
+ BridgeDB(1),
+ UserProvided(2);
+
+ private int source;
+
+ BridgeSource(final int source) {
+ this.source = source;
}
- public enum ProxyType {
- Invalid(-1),
- Socks4(0),
- Socks5(1),
- HTTPS(2);
-
- private int type;
-
- ProxyType(final int type) {
- this.type = type;
- }
-
- public int toInt() {
- return type;
- }
-
- public static ProxyType fromInt(int i) {
- switch (i) {
- case -1: return Invalid;
- case 0: return Socks4;
- case 1: return Socks5;
- case 2: return HTTPS;
- }
- return Invalid;
- }
+ public static BridgeSource fromInt(int i) {
+ switch (i) {
+ case -1:
+ return Invalid;
+ case 0:
+ return BuiltIn;
+ case 1:
+ return BridgeDB;
+ case 2:
+ return UserProvided;
+ }
+ return Invalid;
}
- public enum BridgeBuiltinType {
- /* TorSettings.sys.mjs ~ln43: string: obfs4|meek-azure|snowflake|etc */
- Invalid("invalid"),
- Obfs4("obfs4"),
- MeekAzure("meek-azure"),
- Snowflake("snowflake");
+ public int toInt() {
+ return this.source;
+ }
+ }
+ public enum ProxyType {
+ Invalid(-1),
+ Socks4(0),
+ Socks5(1),
+ HTTPS(2);
- private String type;
+ private int type;
- BridgeBuiltinType(String type) {
- this.type = type;
- }
+ ProxyType(final int type) {
+ this.type = type;
+ }
- public String toString() {
- return type;
- }
+ public int toInt() {
+ return type;
+ }
- public static BridgeBuiltinType fromString(String s) {
- switch (s) {
- case "obfs4": return Obfs4;
- case "meek-azure": return MeekAzure;
- case "snowflake": return Snowflake;
- }
- return Invalid;
- }
+ public static ProxyType fromInt(int i) {
+ switch (i) {
+ case -1:
+ return Invalid;
+ case 0:
+ return Socks4;
+ case 1:
+ return Socks5;
+ case 2:
+ return HTTPS;
+ }
+ return Invalid;
+ }
+ }
+
+ public enum BridgeBuiltinType {
+ /* TorSettings.sys.mjs ~ln43: string: obfs4|meek-azure|snowflake|etc */
+ Invalid("invalid"),
+ Obfs4("obfs4"),
+ MeekAzure("meek-azure"),
+ Snowflake("snowflake");
+
+ private String type;
+ BridgeBuiltinType(String type) {
+ this.type = type;
}
- private boolean loaded = false;
+ public String toString() {
+ return type;
+ }
- public boolean enabled = true;
+ public static BridgeBuiltinType fromString(String s) {
+ switch (s) {
+ case "obfs4":
+ return Obfs4;
+ case "meek-azure":
+ return MeekAzure;
+ case "snowflake":
+ return Snowflake;
+ }
+ return Invalid;
+ }
+ }
- public boolean quickstart = false;
+ private boolean loaded = false;
- // bridges section
- public boolean bridgesEnabled = false;
- public BridgeSource bridgesSource = BridgeSource.Invalid;
- public BridgeBuiltinType bridgesBuiltinType = BridgeBuiltinType.Invalid;
- public String[] bridgeBridgeStrings;
+ public boolean enabled = true;
- // proxy section
- public boolean proxyEnabled = false;
- public ProxyType proxyType = ProxyType.Invalid;
- public String proxyAddress = "";
- public int proxyPort = 0;
- public String proxyUsername = "";
- public String proxyPassword = "";
+ public boolean quickstart = false;
- // firewall section
- public boolean firewallEnabled = false;
- public int[] firewallAllowedPorts;
+ // bridges section
+ public boolean bridgesEnabled = false;
+ public BridgeSource bridgesSource = BridgeSource.Invalid;
+ public BridgeBuiltinType bridgesBuiltinType = BridgeBuiltinType.Invalid;
+ public String[] bridgeBridgeStrings;
- public TorSettings() {
- }
+ // proxy section
+ public boolean proxyEnabled = false;
+ public ProxyType proxyType = ProxyType.Invalid;
+ public String proxyAddress = "";
+ public int proxyPort = 0;
+ public String proxyUsername = "";
+ public String proxyPassword = "";
+
+ // firewall section
+ public boolean firewallEnabled = false;
+ public int[] firewallAllowedPorts;
+
+ public TorSettings() {}
+
+ public TorSettings(GeckoBundle bundle) {
+ try {
+ GeckoBundle qs = bundle.getBundle("quickstart");
+ GeckoBundle bridges = bundle.getBundle("bridges");
+ GeckoBundle proxy = bundle.getBundle("proxy");
+ GeckoBundle firewall = bundle.getBundle("firewall");
+
+ bridgesEnabled = bridges.getBoolean("enabled");
+ bridgesSource = BridgeSource.fromInt(bridges.getInt("source"));
+ bridgesBuiltinType = BridgeBuiltinType.fromString(bridges.getString("builtin_type"));
+ bridgeBridgeStrings = bridges.getStringArray("bridge_strings");
- public TorSettings(GeckoBundle bundle) {
- try {
- GeckoBundle qs = bundle.getBundle("quickstart");
- GeckoBundle bridges = bundle.getBundle("bridges");
- GeckoBundle proxy = bundle.getBundle("proxy");
- GeckoBundle firewall = bundle.getBundle("firewall");
-
- bridgesEnabled = bridges.getBoolean("enabled");
- bridgesSource = BridgeSource.fromInt(bridges.getInt("source"));
- bridgesBuiltinType = BridgeBuiltinType.fromString(bridges.getString("builtin_type"));
- bridgeBridgeStrings = bridges.getStringArray("bridge_strings");
-
- quickstart = qs.getBoolean("enabled");
-
- firewallEnabled = firewall.getBoolean("enabled");
- firewallAllowedPorts = firewall.getIntArray("allowed_ports");
-
- proxyEnabled = proxy.getBoolean("enabled");
- proxyAddress = proxy.getString("address");
- proxyUsername = proxy.getString("username");
- proxyPassword = proxy.getString("password");
- proxyPort = proxy.getInt("port");
- proxyType = ProxyType.fromInt(proxy.getInt("type"));
-
- loaded = true;
- } catch (Exception e) {
- Log.e("TorSettings", "bundle access error: " + e.toString(), e);
- }
+ quickstart = qs.getBoolean("enabled");
+
+ firewallEnabled = firewall.getBoolean("enabled");
+ firewallAllowedPorts = firewall.getIntArray("allowed_ports");
+
+ proxyEnabled = proxy.getBoolean("enabled");
+ proxyAddress = proxy.getString("address");
+ proxyUsername = proxy.getString("username");
+ proxyPassword = proxy.getString("password");
+ proxyPort = proxy.getInt("port");
+ proxyType = ProxyType.fromInt(proxy.getInt("type"));
+
+ loaded = true;
+ } catch (Exception e) {
+ Log.e("TorSettings", "bundle access error: " + e.toString(), e);
}
+ }
- public GeckoBundle asGeckoBundle() {
- GeckoBundle bundle = new GeckoBundle();
+ public GeckoBundle asGeckoBundle() {
+ GeckoBundle bundle = new GeckoBundle();
- GeckoBundle qs = new GeckoBundle();
- GeckoBundle bridges = new GeckoBundle();
- GeckoBundle proxy = new GeckoBundle();
- GeckoBundle firewall = new GeckoBundle();
+ GeckoBundle qs = new GeckoBundle();
+ GeckoBundle bridges = new GeckoBundle();
+ GeckoBundle proxy = new GeckoBundle();
+ GeckoBundle firewall = new GeckoBundle();
- bridges.putBoolean("enabled", bridgesEnabled);
- bridges.putInt("source", bridgesSource.toInt());
- bridges.putString("builtin_type", bridgesBuiltinType.toString());
- bridges.putStringArray("bridge_strings", bridgeBridgeStrings);
+ bridges.putBoolean("enabled", bridgesEnabled);
+ bridges.putInt("source", bridgesSource.toInt());
+ bridges.putString("builtin_type", bridgesBuiltinType.toString());
+ bridges.putStringArray("bridge_strings", bridgeBridgeStrings);
- qs.putBoolean("enabled", quickstart);
+ qs.putBoolean("enabled", quickstart);
- firewall.putBoolean("enabled", firewallEnabled);
- firewall.putIntArray("allowed_ports", firewallAllowedPorts);
+ firewall.putBoolean("enabled", firewallEnabled);
+ firewall.putIntArray("allowed_ports", firewallAllowedPorts);
- proxy.putBoolean("enabled", proxyEnabled);
- proxy.putString("address", proxyAddress);
- proxy.putString("username", proxyUsername);
- proxy.putString("password", proxyPassword);
- proxy.putInt("port", proxyPort);
- proxy.putInt("type", proxyType.toInt());
+ proxy.putBoolean("enabled", proxyEnabled);
+ proxy.putString("address", proxyAddress);
+ proxy.putString("username", proxyUsername);
+ proxy.putString("password", proxyPassword);
+ proxy.putInt("port", proxyPort);
+ proxy.putInt("type", proxyType.toInt());
- bundle.putBundle("quickstart", qs);
- bundle.putBundle("bridges", bridges);
- bundle.putBundle("proxy", proxy);
- bundle.putBundle("firewall", firewall);
+ bundle.putBundle("quickstart", qs);
+ bundle.putBundle("bridges", bridges);
+ bundle.putBundle("proxy", proxy);
+ bundle.putBundle("firewall", firewall);
- return bundle;
- }
+ return bundle;
+ }
- public boolean isLoaded() {
- return this.loaded;
- }
+ public boolean isLoaded() {
+ return this.loaded;
+ }
}
=====================================
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebRequest.java
=====================================
@@ -49,9 +49,7 @@ public class WebRequest extends WebMessage {
/** The value of the Referer header for this request. */
public final @Nullable String referrer;
- /**
- * The value of the origin of this request.
- */
+ /** The value of the origin of this request. */
public final @Nullable String origin;
@Retention(RetentionPolicy.SOURCE)
@@ -248,10 +246,10 @@ public class WebRequest extends WebMessage {
* @param origin A URI String
* @return This Builder instance.
*/
- public @NonNull Builder origin(final @Nullable String origin) {
- mOrigin = origin;
- return this;
- }
+ public @NonNull Builder origin(final @Nullable String origin) {
+ mOrigin = origin;
+ return this;
+ }
/**
* @return A {@link WebRequest} constructed with the values from this Builder instance.
=====================================
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/androidlegacysettings/Prefs.java
=====================================
@@ -2,71 +2,68 @@ package org.mozilla.geckoview.androidlegacysettings;
import android.content.Context;
import android.content.SharedPreferences;
-import org.mozilla.gecko.GeckoAppShell;
-
import java.util.Locale;
+import org.mozilla.gecko.GeckoAppShell;
// tor-android-service utils/Prefs.java
/* package */ class Prefs {
- private final static String PREF_BRIDGES_ENABLED = "pref_bridges_enabled";
- private final static String PREF_BRIDGES_LIST = "pref_bridges_list";
+ private static final String PREF_BRIDGES_ENABLED = "pref_bridges_enabled";
+ private static final String PREF_BRIDGES_LIST = "pref_bridges_list";
- private static SharedPreferences prefs;
+ private static SharedPreferences prefs;
- // OrbotConstants
- private final static String PREF_TOR_SHARED_PREFS = "org.torproject.android_preferences";
+ // OrbotConstants
+ private static final String PREF_TOR_SHARED_PREFS = "org.torproject.android_preferences";
+ // tor-android-service utils/TorServiceUtil.java
- // tor-android-service utils/TorServiceUtil.java
-
- private static void setContext() {
- if (prefs == null) {
- prefs = GeckoAppShell.getApplicationContext().getSharedPreferences(PREF_TOR_SHARED_PREFS,
- Context.MODE_MULTI_PROCESS);
- }
+ private static void setContext() {
+ if (prefs == null) {
+ prefs =
+ GeckoAppShell.getApplicationContext()
+ .getSharedPreferences(PREF_TOR_SHARED_PREFS, Context.MODE_MULTI_PROCESS);
}
-
- public static boolean getBoolean(String key, boolean def) {
- setContext();
- return prefs.getBoolean(key, def);
- }
-
- public static void putBoolean(String key, boolean value) {
- setContext();
- prefs.edit().putBoolean(key, value).apply();
- }
-
- public static void putString(String key, String value) {
- setContext();
- prefs.edit().putString(key, value).apply();
+ }
+
+ public static boolean getBoolean(String key, boolean def) {
+ setContext();
+ return prefs.getBoolean(key, def);
+ }
+
+ public static void putBoolean(String key, boolean value) {
+ setContext();
+ prefs.edit().putBoolean(key, value).apply();
+ }
+
+ public static void putString(String key, String value) {
+ setContext();
+ prefs.edit().putString(key, value).apply();
+ }
+
+ public static String getString(String key, String def) {
+ setContext();
+ return prefs.getString(key, def);
+ }
+
+ public static boolean bridgesEnabled() {
+ setContext();
+ // for Locale.getDefault().getLanguage().equals("fa"), bridges were enabled by default (and
+ // it was meek). This was a default set in 2019 code, but it is not a good default anymore,
+ // so we removed the check.
+ return prefs.getBoolean(PREF_BRIDGES_ENABLED, false);
+ }
+
+ public static String getBridgesList() {
+ setContext();
+ String list = prefs.getString(PREF_BRIDGES_LIST, "");
+ // list might be empty if the default PT was used, so check also if bridges are enabled.
+ if (list.isEmpty() && prefs.getBoolean(PREF_BRIDGES_ENABLED, false)) {
+ // Even though the check on the fa locale is not good to enable bridges by default, we
+ // still check it here, because if the list was empty, it was likely that it was the
+ // choice for users with this locale.
+ return (Locale.getDefault().getLanguage().equals("fa")) ? "meek" : "obfs4";
}
-
- public static String getString(String key, String def) {
- setContext();
- return prefs.getString(key, def);
- }
-
- public static boolean bridgesEnabled() {
- setContext();
- // for Locale.getDefault().getLanguage().equals("fa"), bridges were enabled by default (and
- // it was meek). This was a default set in 2019 code, but it is not a good default anymore,
- // so we removed the check.
- return prefs.getBoolean(PREF_BRIDGES_ENABLED, false);
- }
-
- public static String getBridgesList() {
- setContext();
- String list = prefs.getString(PREF_BRIDGES_LIST, "");
- // list might be empty if the default PT was used, so check also if bridges are enabled.
- if (list.isEmpty() && prefs.getBoolean(PREF_BRIDGES_ENABLED, false)) {
- // Even though the check on the fa locale is not good to enable bridges by default, we
- // still check it here, because if the list was empty, it was likely that it was the
- // choice for users with this locale.
- return (Locale.getDefault().getLanguage().equals("fa")) ? "meek": "obfs4";
- }
- return list;
- }
-
-
+ return list;
+ }
}
=====================================
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/androidlegacysettings/TorLegacyAndroidSettings.java
=====================================
@@ -4,70 +4,71 @@ import org.mozilla.geckoview.TorSettings;
public class TorLegacyAndroidSettings {
- private static String PREF_USE_MOZ_PREFS = "tor_use_moz_prefs";
+ private static String PREF_USE_MOZ_PREFS = "tor_use_moz_prefs";
- public static boolean unmigrated() {
- return !Prefs.getBoolean(PREF_USE_MOZ_PREFS, false);
- }
+ public static boolean unmigrated() {
+ return !Prefs.getBoolean(PREF_USE_MOZ_PREFS, false);
+ }
- public static void setUnmigrated() {
- Prefs.putBoolean(PREF_USE_MOZ_PREFS, false);
- }
+ public static void setUnmigrated() {
+ Prefs.putBoolean(PREF_USE_MOZ_PREFS, false);
+ }
- public static void setMigrated() {
- Prefs.putBoolean(PREF_USE_MOZ_PREFS, true);
- }
+ public static void setMigrated() {
+ Prefs.putBoolean(PREF_USE_MOZ_PREFS, true);
+ }
- public static TorSettings loadTorSettings() {
- TorSettings settings = new TorSettings();
+ public static TorSettings loadTorSettings() {
+ TorSettings settings = new TorSettings();
- // always true, tor is enabled in TB
- settings.enabled = true;
+ // always true, tor is enabled in TB
+ settings.enabled = true;
- // firefox-android disconnected quick start a while ago so it's untracked
- settings.quickstart = false;
+ // firefox-android disconnected quick start a while ago so it's untracked
+ settings.quickstart = false;
- settings.bridgesEnabled = Prefs.bridgesEnabled();
+ settings.bridgesEnabled = Prefs.bridgesEnabled();
- // tor-android-service CustomTorInstaller.java
-/*
- BridgesList is an overloaded field, which can cause some confusion.
- The list can be:
- 1) a filter like obfs4, meek, or snowflake OR
- 2) it can be a custom bridge
- For (1), we just pass back all bridges, the filter will occur
- elsewhere in the library.
- For (2) we return the bridge list as a raw stream.
- If length is greater than 9, then we know this is a custom bridge
- */
- String userDefinedBridgeList = Prefs.getBridgesList();
- boolean userDefinedBridge = userDefinedBridgeList.length() > 9;
- // Terrible hack. Must keep in sync with topl::addBridgesFromResources.
- if (!userDefinedBridge) {
- settings.bridgesSource = TorSettings.BridgeSource.BuiltIn;
- switch (userDefinedBridgeList) {
- case "obfs4":
- case "snowflake":
- settings.bridgesBuiltinType = TorSettings.BridgeBuiltinType.fromString(userDefinedBridgeList);
- break;
- case "meek":
- settings.bridgesBuiltinType = TorSettings.BridgeBuiltinType.MeekAzure;
- break;
- default:
- settings.bridgesSource = TorSettings.BridgeSource.Invalid;
- break;
- }
- } else {
- settings.bridgesSource = TorSettings.BridgeSource.UserProvided; // user provided
- settings.bridgeBridgeStrings = userDefinedBridgeList.split("\r\n");
- }
+ // tor-android-service CustomTorInstaller.java
+ /*
+ BridgesList is an overloaded field, which can cause some confusion.
+ The list can be:
+ 1) a filter like obfs4, meek, or snowflake OR
+ 2) it can be a custom bridge
+ For (1), we just pass back all bridges, the filter will occur
+ elsewhere in the library.
+ For (2) we return the bridge list as a raw stream.
+ If length is greater than 9, then we know this is a custom bridge
+ */
+ String userDefinedBridgeList = Prefs.getBridgesList();
+ boolean userDefinedBridge = userDefinedBridgeList.length() > 9;
+ // Terrible hack. Must keep in sync with topl::addBridgesFromResources.
+ if (!userDefinedBridge) {
+ settings.bridgesSource = TorSettings.BridgeSource.BuiltIn;
+ switch (userDefinedBridgeList) {
+ case "obfs4":
+ case "snowflake":
+ settings.bridgesBuiltinType =
+ TorSettings.BridgeBuiltinType.fromString(userDefinedBridgeList);
+ break;
+ case "meek":
+ settings.bridgesBuiltinType = TorSettings.BridgeBuiltinType.MeekAzure;
+ break;
+ default:
+ settings.bridgesSource = TorSettings.BridgeSource.Invalid;
+ break;
+ }
+ } else {
+ settings.bridgesSource = TorSettings.BridgeSource.UserProvided; // user provided
+ settings.bridgeBridgeStrings = userDefinedBridgeList.split("\r\n");
+ }
- // Tor Browser Android doesn't take proxy and firewall settings
- settings.proxyEnabled = false;
+ // Tor Browser Android doesn't take proxy and firewall settings
+ settings.proxyEnabled = false;
- settings.firewallEnabled = false;
- settings.firewallAllowedPorts = new int[0];
+ settings.firewallEnabled = false;
+ settings.firewallAllowedPorts = new int[0];
- return settings;
- }
+ return settings;
+ }
}
=====================================
toolkit/modules/DomainFrontedRequests.sys.mjs
=====================================
@@ -444,7 +444,7 @@ export class DomainFrontRequestBuilder {
async init(reflector, front) {
if (this.#inited) {
- throw new Error("MoatRPC: Already initialized");
+ throw new Error("DomainFrontRequestBuilder: Already initialized");
}
const meekTransport =
@@ -464,7 +464,7 @@ export class DomainFrontRequestBuilder {
buildHttpHandler(uriString) {
if (!this.#inited) {
- throw new Error("MoatRPC: Not initialized");
+ throw new Error("DomainFrontRequestBuilder: Not initialized");
}
const { proxyType, proxyAddress, proxyPort, proxyUsername, proxyPassword } =
=====================================
toolkit/modules/Moat.sys.mjs
=====================================
@@ -119,7 +119,7 @@ export class MoatRPC {
ch.requestMethod = "HEAD";
const listener = new InternetTestResponseListener();
- await ch.asyncOpen(listener, ch);
+ ch.asyncOpen(listener, ch);
return listener.status;
}
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/70283a…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/70283a…
You're receiving this email because of your account on gitlab.torproject.org.
1
0