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

[tor-commits] [tor-browser] 62/69: Bug 16940: After update, load local change notes.



This is an automated email from the git hooks/post-receive script.

richard pushed a commit to branch tor-browser-102.2.0esr-12.0-3
in repository tor-browser.

commit f0b8a516129d8ce7a73e336439d2471e25d2e9fb
Author: Kathy Brade <brade@xxxxxxxxxxxxxxxxx>
AuthorDate: Wed Nov 25 11:36:20 2015 -0500

    Bug 16940: After update, load local change notes.
    
    Add an about:tbupdate page that displays the first section from
    TorBrowser/Docs/ChangeLog.txt and includes a link to the remote
    post-update page (typically our blog entry for the release).
    
    Always load about:tbupdate in a content process, but implement the
    code that reads the file system (changelog) in the chrome process
    for compatibility with future sandboxing efforts.
    
    Also fix bug 29440. Now about:tbupdate is styled as a fairly simple
    changelog page that is designed to be displayed via a link that is on
    about:tor.
---
 browser/actors/AboutTBUpdateChild.jsm              |  12 +++
 browser/actors/AboutTBUpdateParent.jsm             | 120 +++++++++++++++++++++
 browser/actors/moz.build                           |   6 ++
 .../base/content/abouttbupdate/aboutTBUpdate.css   |  74 +++++++++++++
 .../base/content/abouttbupdate/aboutTBUpdate.js    |  27 +++++
 .../base/content/abouttbupdate/aboutTBUpdate.xhtml |  39 +++++++
 browser/base/content/browser.js                    |   4 +
 browser/base/jar.mn                                |   5 +
 browser/components/BrowserContentHandler.jsm       |  55 +++++++---
 browser/components/BrowserGlue.jsm                 |  15 +++
 browser/components/about/AboutRedirector.cpp       |   7 ++
 browser/components/about/components.conf           |   3 +
 browser/components/moz.build                       |   5 +-
 .../locales/en-US/chrome/browser/aboutTBUpdate.dtd |   8 ++
 browser/locales/jar.mn                             |   3 +
 15 files changed, 368 insertions(+), 15 deletions(-)

diff --git a/browser/actors/AboutTBUpdateChild.jsm b/browser/actors/AboutTBUpdateChild.jsm
new file mode 100644
index 0000000000000..4670da19b3db0
--- /dev/null
+++ b/browser/actors/AboutTBUpdateChild.jsm
@@ -0,0 +1,12 @@
+// Copyright (c) 2020, The Tor Project, Inc.
+// See LICENSE for licensing information.
+//
+// vim: set sw=2 sts=2 ts=8 et syntax=javascript:
+
+var EXPORTED_SYMBOLS = ["AboutTBUpdateChild"];
+
+const { RemotePageChild } = ChromeUtils.import(
+  "resource://gre/actors/RemotePageChild.jsm"
+);
+
+class AboutTBUpdateChild extends RemotePageChild {}
diff --git a/browser/actors/AboutTBUpdateParent.jsm b/browser/actors/AboutTBUpdateParent.jsm
new file mode 100644
index 0000000000000..56a10394565aa
--- /dev/null
+++ b/browser/actors/AboutTBUpdateParent.jsm
@@ -0,0 +1,120 @@
+// Copyright (c) 2020, The Tor Project, Inc.
+// See LICENSE for licensing information.
+//
+// vim: set sw=2 sts=2 ts=8 et syntax=javascript:
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["AboutTBUpdateParent"];
+
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
+const { AppConstants } = ChromeUtils.import(
+  "resource://gre/modules/AppConstants.jsm"
+);
+
+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.
+ */
+class AboutTBUpdateParent extends JSWindowActorParent {
+  receiveMessage(aMessage) {
+    if (aMessage.name == kRequestUpdateMessageName) {
+      return this.releaseNoteInfo;
+    }
+    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 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.
+  //
+  // On Mac OS, when building with --enable-tor-browser-data-outside-app-dir
+  // to support Gatekeeper signing, the ChangeLog.txt file is located in
+  // TorBrowser.app/Contents/Resources/TorBrowser/Docs/.
+  get releaseNoteInfo() {
+    let info = { moreInfoURL: this.moreInfoURL };
+
+    try {
+      let f;
+      if (AppConstants.TOR_BROWSER_DATA_OUTSIDE_APP_DIR) {
+        // "XREExeF".parent is the directory that contains firefox, i.e.,
+        // Browser/ or, on Mac OS, TorBrowser.app/Contents/MacOS/.
+        f = Services.dirsvc.get("XREExeF", Ci.nsIFile).parent;
+        if (AppConstants.platform === "macosx") {
+          f = f.parent;
+          f.append("Resources");
+        }
+        f.append("TorBrowser");
+      } else {
+        // "DefProfRt" is .../TorBrowser/Data/Browser
+        f = Services.dirsvc.get("DefProfRt", Ci.nsIFile);
+        f = f.parent.parent; // Remove "Data/Browser"
+      }
+
+      f.append("Docs");
+      f.append("ChangeLog.txt");
+
+      let fs = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(
+        Ci.nsIFileInputStream
+      );
+      fs.init(f, -1, 0, 0);
+      let s = NetUtil.readInputStreamToString(fs, fs.available());
+      fs.close();
+
+      // Truncate at the first empty line.
+      s = s.replace(/[\r\n][\r\n][\s\S]*$/m, "");
+
+      // Split into first line (version plus releaseDate) and
+      // remainder (releaseNotes).
+      // This first match() uses multiline mode with two capture groups:
+      //   first line: (.*$)
+      //   remaining lines: ([\s\S]+)
+      //     [\s\S] matches all characters including end of line. This trick
+      //     is needed because when using JavaScript regex in multiline mode,
+      //     . does not match an end of line character.
+      let matchArray = s.match(/(.*$)\s*([\s\S]+)/m);
+      if (matchArray && matchArray.length == 3) {
+        info.releaseNotes = matchArray[2];
+        let line1 = matchArray[1];
+        // Extract the version and releaseDate. The first line looks like:
+        //   Tor Browser 8.5 -- May 1 2019
+        // The regex uses two capture groups:
+        //   text that does not include a hyphen: (^[^-]*)
+        //   remaining text: (.*$)
+        // In between we match optional whitespace, one or more hyphens, and
+        // optional whitespace by using: \s*-+\s*
+        matchArray = line1.match(/(^[^-]*)\s*-+\s*(.*$)/);
+        if (matchArray && matchArray.length == 3) {
+          info.version = matchArray[1];
+          info.releaseDate = matchArray[2];
+        } else {
+          info.version = line1; // Match failed: return entire line in version.
+        }
+      } else {
+        info.releaseNotes = s; // Only one line: use as releaseNotes.
+      }
+    } catch (e) {}
+
+    return info;
+  }
+}
diff --git a/browser/actors/moz.build b/browser/actors/moz.build
index 5a2c1796fb5df..d9c06c795a3d6 100644
--- a/browser/actors/moz.build
+++ b/browser/actors/moz.build
@@ -95,3 +95,9 @@ FINAL_TARGET_FILES.actors += [
 BROWSER_CHROME_MANIFESTS += [
     "test/browser/browser.ini",
 ]
+
+if CONFIG["TOR_BROWSER_UPDATE"]:
+    FINAL_TARGET_FILES.actors += [
+        "AboutTBUpdateChild.jsm",
+        "AboutTBUpdateParent.jsm",
+    ]
diff --git a/browser/base/content/abouttbupdate/aboutTBUpdate.css b/browser/base/content/abouttbupdate/aboutTBUpdate.css
new file mode 100644
index 0000000000000..7c1a34b77f176
--- /dev/null
+++ b/browser/base/content/abouttbupdate/aboutTBUpdate.css
@@ -0,0 +1,74 @@
+/*
+ * 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);
+  background-attachment: fixed;
+  background-size: 100% 100%;
+}
+
+a {
+  color: var(--abouttor-text-color);
+}
+
+.two-column-grid {
+  display: inline-grid;
+  grid-template-columns: auto auto;
+  grid-column-gap: 50px;
+  margin: 10px 0px 0px 50px;
+}
+
+.two-column-grid div {
+  margin-top: 40px;
+  align-self: baseline;  /* Align baseline of text across the row. */
+}
+
+.label-column {
+  font-size: 14px;
+  font-weight: 400;
+}
+
+/*
+ * Use a reduced top margin to bring the row that contains the
+ * "visit our website" link closer to the row that precedes it. This
+ * looks better because the "visit our website" row does not have a
+ * label in the left column.
+ */
+div.more-info-row {
+  margin-top: 5px;
+  font-size: 14px;
+}
+
+#version-content {
+  font-size: 50px;
+  font-weight: 300;
+}
+
+body:not([havereleasedate]) .release-date-cell {
+  display: none;
+}
+
+#releasedate-content {
+  font-size: 17px;
+}
+
+#releasenotes-label {
+  align-self: start;  /* Anchor "Release Notes" label at the top. */
+}
+
+#releasenotes-content {
+  font-family: monospace;
+  font-size: 15px;
+  white-space: pre;
+}
diff --git a/browser/base/content/abouttbupdate/aboutTBUpdate.js b/browser/base/content/abouttbupdate/aboutTBUpdate.js
new file mode 100644
index 0000000000000..ec070e2cb1312
--- /dev/null
+++ b/browser/base/content/abouttbupdate/aboutTBUpdate.js
@@ -0,0 +1,27 @@
+// 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/frame-script */
+
+// aData may contain the following string properties:
+//   version
+//   releaseDate
+//   moreInfoURL
+//   releaseNotes
+function onUpdate(aData) {
+  document.getElementById("version-content").textContent = aData.version;
+  if (aData.releaseDate) {
+    document.body.setAttribute("havereleasedate", "true");
+    document.getElementById("releasedate-content").textContent =
+      aData.releaseDate;
+  }
+  if (aData.moreInfoURL) {
+    document.getElementById("infolink").setAttribute("href", aData.moreInfoURL);
+  }
+  document.getElementById("releasenotes-content").textContent =
+    aData.releaseNotes;
+}
+
+RPMSendQuery("FetchUpdateData").then(onUpdate);
diff --git a/browser/base/content/abouttbupdate/aboutTBUpdate.xhtml b/browser/base/content/abouttbupdate/aboutTBUpdate.xhtml
new file mode 100644
index 0000000000000..8489cfef5083a
--- /dev/null
+++ b/browser/base/content/abouttbupdate/aboutTBUpdate.xhtml
@@ -0,0 +1,39 @@
+<?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 % globalDTD SYSTEM "chrome://global/locale/global.dtd">
+  %globalDTD;
+  <!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"/>
+</head>
+<body dir="&locale.dir;">
+<div class="two-column-grid">
+  <div class="label-column">&aboutTBUpdate.version;</div>
+  <div id="version-content"/>
+
+  <div class="label-column release-date-cell">&aboutTBUpdate.releaseDate;</div>
+  <div id="releasedate-content" class="release-date-cell"/>
+
+  <div class="more-info-row"/>
+  <div class="more-info-row">&aboutTBUpdate.linkPrefix;<a id="infolink">&aboutTBUpdate.linkLabel;</a>&aboutTBUpdate.linkSuffix;</div>
+
+  <div id="releasenotes-label"
+       class="label-column">&aboutTBUpdate.releaseNotes;</div>
+  <div id="releasenotes-content"></div>
+</div>
+</body>
+</html>
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index 01b3b704a4037..c06aa94d1d8c3 100644
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -658,6 +658,10 @@ var gInitialPages = [
   "about:welcomeback",
 ];
 
+if (AppConstants.TOR_BROWSER_UPDATE) {
+  gInitialPages.push("about:tbupdate");
+}
+
 function isInitialPage(url) {
   if (!(url instanceof Ci.nsIURI)) {
     try {
diff --git a/browser/base/jar.mn b/browser/base/jar.mn
index d2b075a50f398..02ee0b3595153 100644
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -34,6 +34,11 @@ browser.jar:
         content/browser/aboutTabCrashed.css           (content/aboutTabCrashed.css)
         content/browser/aboutTabCrashed.js            (content/aboutTabCrashed.js)
         content/browser/aboutTabCrashed.xhtml         (content/aboutTabCrashed.xhtml)
+#ifdef TOR_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/browser.css                   (content/browser.css)
         content/browser/browser.js                    (content/browser.js)
 *       content/browser/browser.xhtml                 (content/browser.xhtml)
diff --git a/browser/components/BrowserContentHandler.jsm b/browser/components/BrowserContentHandler.jsm
index 714a5fac8bf03..e2b06b4fe8a04 100644
--- a/browser/components/BrowserContentHandler.jsm
+++ b/browser/components/BrowserContentHandler.jsm
@@ -653,6 +653,23 @@ nsBrowserContentHandler.prototype = {
       }
     }
 
+    // Retrieve the home page early so we can compare it against about:tor
+    // to decide whether or not we need an override page (second tab) after
+    // an update was applied.
+    var startPage = "";
+    try {
+      var choice = prefb.getIntPref("browser.startup.page");
+      if (choice == 1 || choice == 3) {
+        startPage = HomePage.get();
+      }
+    } catch (e) {
+      Cu.reportError(e);
+    }
+
+    if (startPage == "about:blank") {
+      startPage = "";
+    }
+
     var override;
     var overridePage = "";
     var additionalPage = "";
@@ -695,6 +712,16 @@ 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 = SessionStartup.isAutomaticRestoreEnabled();
 
             overridePage = Services.urlFormatter.formatURLPref(
@@ -716,6 +743,20 @@ nsBrowserContentHandler.prototype = {
               "%OLD_TOR_BROWSER_VERSION%",
               old_tbversion
             );
+#ifdef TOR_BROWSER_UPDATE
+            if (overridePage)
+            {
+              prefb.setCharPref("torbrowser.post_update.url", overridePage);
+              prefb.setBoolPref("torbrowser.post_update.shouldNotify", true);
+              // If the user's homepage is about:tor, we will inform them
+              // about the update on that page; otherwise, we arrange to
+              // open about:tor in a secondary tab.
+              if (startPage === "about:tor")
+                overridePage = "";
+              else
+                overridePage = "about:tor";
+            }
+#endif
             break;
           case OVERRIDE_NEW_BUILD_ID:
             if (UpdateManager.readyUpdate) {
@@ -788,20 +829,6 @@ nsBrowserContentHandler.prototype = {
       }
     }
 
-    var startPage = "";
-    try {
-      var choice = prefb.getIntPref("browser.startup.page");
-      if (choice == 1 || choice == 3) {
-        startPage = HomePage.get();
-      }
-    } catch (e) {
-      Cu.reportError(e);
-    }
-
-    if (startPage == "about:blank") {
-      startPage = "";
-    }
-
     let skipStartPage =
       override == OVERRIDE_NEW_PROFILE &&
       prefb.getBoolPref("browser.startup.firstrunSkipsHomepage");
diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm
index 0092d25948e79..fe46dec2c42db 100644
--- a/browser/components/BrowserGlue.jsm
+++ b/browser/components/BrowserGlue.jsm
@@ -794,6 +794,21 @@ let JSWINDOWACTORS = {
   },
 };
 
+if (AppConstants.TOR_BROWSER_UPDATE) {
+  JSWINDOWACTORS.AboutTBUpdate = {
+    parent: {
+      moduleURI: "resource:///actors/AboutTBUpdateParent.jsm",
+    },
+    child: {
+      moduleURI: "resource:///actors/AboutTBUpdateChild.jsm",
+      events: {
+        DOMWindowCreated: { capture: true },
+      },
+    },
+    matches: ["about:tbupdate"],
+  };
+}
+
 XPCOMUtils.defineLazyGetter(
   this,
   "WeaveService",
diff --git a/browser/components/about/AboutRedirector.cpp b/browser/components/about/AboutRedirector.cpp
index 0a495a223e3eb..faf809728352f 100644
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -133,6 +133,13 @@ static const RedirEntry kRedirMap[] = {
          nsIAboutModule::HIDE_FROM_ABOUTABOUT},
     {"restartrequired", "chrome://browser/content/aboutRestartRequired.xhtml",
      nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::HIDE_FROM_ABOUTABOUT},
+#ifdef TOR_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
     {"torconnect", "chrome://browser/content/torconnect/aboutTorConnect.xhtml",
      nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
          nsIAboutModule::URI_CAN_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT |
diff --git a/browser/components/about/components.conf b/browser/components/about/components.conf
index 6095653409cd8..a1eb66c9fc95b 100644
--- a/browser/components/about/components.conf
+++ b/browser/components/about/components.conf
@@ -34,6 +34,9 @@ pages = [
     'welcomeback',
 ]
 
+if defined('TOR_BROWSER_UPDATE'):
+    pages.append('tbupdate')
+
 Classes = [
     {
         'cid': '{7e4bb6ad-2fc4-4dc6-89ef-23e8e5ccf980}',
diff --git a/browser/components/moz.build b/browser/components/moz.build
index ab1dac40dfabe..8033a5985ed0f 100644
--- a/browser/components/moz.build
+++ b/browser/components/moz.build
@@ -93,11 +93,14 @@ EXTRA_COMPONENTS += [
 ]
 
 EXTRA_JS_MODULES += [
-    "BrowserContentHandler.jsm",
     "BrowserGlue.jsm",
     "distribution.js",
 ]
 
+EXTRA_PP_JS_MODULES += [
+    "BrowserContentHandler.jsm",
+]
+
 BROWSER_CHROME_MANIFESTS += [
     "safebrowsing/content/test/browser.ini",
     "tests/browser/browser.ini",
diff --git a/browser/locales/en-US/chrome/browser/aboutTBUpdate.dtd b/browser/locales/en-US/chrome/browser/aboutTBUpdate.dtd
new file mode 100644
index 0000000000000..2d1e59b40eafd
--- /dev/null
+++ b/browser/locales/en-US/chrome/browser/aboutTBUpdate.dtd
@@ -0,0 +1,8 @@
+<!ENTITY aboutTBUpdate.changelogTitle "Tor Browser Changelog">
+<!ENTITY aboutTBUpdate.updated "Tor Browser has been updated.">
+<!ENTITY aboutTBUpdate.linkPrefix "For the most up-to-date information about this release, ">
+<!ENTITY aboutTBUpdate.linkLabel  "visit our website">
+<!ENTITY aboutTBUpdate.linkSuffix ".">
+<!ENTITY aboutTBUpdate.version "Version">
+<!ENTITY aboutTBUpdate.releaseDate "Release Date">
+<!ENTITY aboutTBUpdate.releaseNotes "Release Notes">
diff --git a/browser/locales/jar.mn b/browser/locales/jar.mn
index 167a695a46a85..2d4c50b8e7d12 100644
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -21,6 +21,9 @@
 @AB_CD@.jar:
 % locale browser @AB_CD@ %locale/browser/
     locale/browser/accounts.properties             (%chrome/browser/accounts.properties)
+#ifdef TOR_BROWSER_UPDATE
+    locale/browser/aboutTBUpdate.dtd               (%chrome/browser/aboutTBUpdate.dtd)
+#endif
     locale/browser/browser.properties              (%chrome/browser/browser.properties)
     locale/browser/customizableui/customizableWidgets.properties (%chrome/browser/customizableui/customizableWidgets.properties)
     locale/browser/uiDensity.properties            (%chrome/browser/uiDensity.properties)

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits