[tor-commits] [meek/master] Have meek-client-torbrowser write the native host manifest.

dcf at torproject.org dcf at torproject.org
Wed Aug 28 05:59:18 UTC 2019


commit c7b99db18bb4f60c5221bf62b7bee3eb0b558434
Author: David Fifield <david at bamsoftware.com>
Date:   Wed Feb 20 13:27:32 2019 -0700

    Have meek-client-torbrowser write the native host manifest.
    
    The WebExtension needs a JSON "host manifest" that both authorizes the
    extension to run a native executable, and tells the browser where to
    find the native executable. The path inside the manifest needs to be an
    absolute path, so we cannot just plunk down a static file; we have to
    know the path to where the browser is installed. meek-client-torbrowser
    rewrites the manifest on each startup, where the browser expects to find
    it.
    
    The is mostly self-contained and compatible with previous behavior, with
    one small exception on windows. On mac and linux, the browser expects to
    find the manifest in a well-known location (relative to $HOME, which in
    our case is inside the browser's directory tree or the ancillary
    TorBrowser-Data directory). But on windows, the path to the manifest
    needs to be stored in the registry. So meek-client-torbrowser not only
    writes the manifest file, it also writes a registry key pointing to the
    file. I'd like to try and find a way to do this that doesn't require
    modifying global state like this.
    
    This patch is tested on linux and windows but not mac.
---
 meek-client-torbrowser/linux.go                  |  7 ++
 meek-client-torbrowser/mac.go                    | 19 +++++-
 meek-client-torbrowser/meek-client-torbrowser.go |  8 +++
 meek-client-torbrowser/nativemanifest.go         | 86 ++++++++++++++++++++++++
 meek-client-torbrowser/windows.go                | 37 +++++++++-
 5 files changed, 155 insertions(+), 2 deletions(-)

diff --git a/meek-client-torbrowser/linux.go b/meek-client-torbrowser/linux.go
index 71b5cfb..f728f1d 100644
--- a/meek-client-torbrowser/linux.go
+++ b/meek-client-torbrowser/linux.go
@@ -15,6 +15,9 @@ const (
 	firefoxProfilePath           = "TorBrowser/Data/Browser/profile.meek-http-helper"
 	torDataDirFirefoxProfilePath = ""
 	profileTemplatePath          = ""
+	// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#Linux
+	helperNativeManifestDir    = "TorBrowser/Data/Browser/.mozilla/native-messaging-hosts"
+	helperNativeExecutablePath = "TorBrowser/Tor/PluggableTransports/meek-http-helper"
 )
 
 func osSpecificCommandSetup(cmd *exec.Cmd) {
@@ -22,3 +25,7 @@ func osSpecificCommandSetup(cmd *exec.Cmd) {
 	// process terminates. Only works on Linux.
 	cmd.SysProcAttr = &syscall.SysProcAttr{Pdeathsig: syscall.SIGTERM}
 }
+
+func installHelperNativeManifest() error {
+	return writeNativeManifestToFile(helperNativeManifestDir, helperNativeExecutablePath)
+}
diff --git a/meek-client-torbrowser/mac.go b/meek-client-torbrowser/mac.go
index f88ed38..995aca5 100644
--- a/meek-client-torbrowser/mac.go
+++ b/meek-client-torbrowser/mac.go
@@ -5,7 +5,11 @@
 
 package main
 
-import "os/exec"
+import (
+	"os"
+	"os/exec"
+	"path/filepath"
+)
 
 const (
 	// During startup of meek-client-torbrowser, the browser profile is
@@ -20,8 +24,21 @@ const (
 	torDataDirFirefoxProfilePath = "PluggableTransports/profile.meek-http-helper"
 	firefoxProfilePath           = "../../../../TorBrowser-Data/Tor/PluggableTransports/profile.meek-http-helper"
 	profileTemplatePath          = "../../Resources/TorBrowser/Tor/PluggableTransports/template-profile.meek-http-helper"
+	helperNativeExecutablePath   = "../Tor/PluggableTransports/meek-http-helper"
 )
 
 func osSpecificCommandSetup(cmd *exec.Cmd) {
 	// nothing
 }
+
+func installHelperNativeManifest() error {
+	var homeDir string
+	torDataDir := os.Getenv("TOR_BROWSER_TOR_DATA_DIR")
+	if torDataDir != "" {
+		homeDir = filepath.Join(torDataDir, "..", "Browser")
+	} else {
+		homeDir = "../../../../TorBrowser-Data/Browser"
+	}
+	// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#Mac_OS_X
+	return writeNativeManifestToFile(filepath.Join(homeDir, "Mozilla", "NativeMessagingHosts"), helperNativeExecutablePath)
+}
diff --git a/meek-client-torbrowser/meek-client-torbrowser.go b/meek-client-torbrowser/meek-client-torbrowser.go
index 6ce7a12..0284280 100644
--- a/meek-client-torbrowser/meek-client-torbrowser.go
+++ b/meek-client-torbrowser/meek-client-torbrowser.go
@@ -242,6 +242,14 @@ func runFirefox() (cmd *exec.Cmd, stdout io.Reader, err error) {
 		return
 	}
 
+	// Install the meek.http.helper.json file that tells the browser where
+	// to find the native component of the meek-http-helper WebExtension.
+	// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests
+	err = installHelperNativeManifest()
+	if err != nil {
+		return
+	}
+
 	cmd = exec.Command(absFirefoxPath, "--headless", "--no-remote", "--profile", profilePath)
 	osSpecificCommandSetup(cmd)
 	cmd.Stderr = os.Stderr
diff --git a/meek-client-torbrowser/nativemanifest.go b/meek-client-torbrowser/nativemanifest.go
new file mode 100644
index 0000000..7c6abc7
--- /dev/null
+++ b/meek-client-torbrowser/nativemanifest.go
@@ -0,0 +1,86 @@
+// This code has to do with the native manifest of the meek-http-helper
+// WebExtension. The native manifest contains the path to the native executable
+// that the WebExtension runs via the native messaging API.
+//
+// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging#App_manifest
+
+package main
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+)
+
+// These values need to match the ones in the webextension directory.
+const (
+	// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/WebExtensions_and_the_Add-on_ID
+	addOnID = "meek-http-helper at bamsoftware.com"
+	// This needs to match the value passed to runtime.connectNative in the
+	// JavaScript code.
+	nativeAppName = "meek.http.helper"
+)
+
+// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#Native_messaging_manifests
+type nativeManifestJSON struct {
+	Name              string   `json:"name"`
+	Description       string   `json:"description"`
+	Path              string   `json:"path"`
+	Type              string   `json:"type"`
+	AllowedExtensions []string `json:"allowed_extensions"`
+}
+
+// manifestDir is the directory of the eventual meek.http.helper.json file (the
+// manifest itself). nativePath is the path to the native executable that is
+// stored inside the manifest.
+func writeNativeManifestToFile(manifestDir, nativePath string) error {
+	// "On Windows, this may be relative to the manifest itself. On OS X and
+	// Linux it must be absolute."
+	absNativePath, err := filepath.Abs(nativePath)
+	if err != nil {
+		return err
+	}
+	manifest := nativeManifestJSON{
+		Name:              nativeAppName,
+		Description:       "Native half of meek-http-helper.",
+		Path:              absNativePath,
+		Type:              "stdio",
+		AllowedExtensions: []string{"meek-http-helper at bamsoftware.com"},
+	}
+
+	err = os.MkdirAll(manifestDir, 0755)
+	if err != nil {
+		return err
+	}
+	// First we'll write the new manifest into a temporary file.
+	tmpFile, err := ioutil.TempFile(manifestDir, nativeAppName+".json.tmp.")
+	if err != nil {
+		return err
+	}
+	// Write the JSON to the temporary file and rename it to the
+	// destination. Wrapped in a lambda to allow early return in case of
+	// error.
+	err = func() error {
+		err = json.NewEncoder(tmpFile).Encode(manifest)
+		if err != nil {
+			return err
+		}
+		err = tmpFile.Close()
+		if err != nil {
+			return err
+		}
+		return os.Rename(tmpFile.Name(), filepath.Join(manifestDir, nativeAppName+".json"))
+	}()
+	// If any error occurred during write/close/rename, try to remove the
+	// temporary file.
+	if err != nil {
+		err := os.Remove(tmpFile.Name())
+		// Log this error but otherwise ignore it.
+		if err != nil {
+			log.Print(err)
+		}
+	}
+	return err
+}
diff --git a/meek-client-torbrowser/windows.go b/meek-client-torbrowser/windows.go
index f837e6e..907d1dc 100644
--- a/meek-client-torbrowser/windows.go
+++ b/meek-client-torbrowser/windows.go
@@ -5,15 +5,50 @@
 
 package main
 
-import "os/exec"
+import (
+	"os/exec"
+	"path/filepath"
+
+	"golang.org/x/sys/windows/registry"
+)
 
 const (
 	firefoxPath                  = "./firefox.exe"
 	firefoxProfilePath           = "TorBrowser/Data/Browser/profile.meek-http-helper"
 	torDataDirFirefoxProfilePath = ""
 	profileTemplatePath          = ""
+	// The location of the host manifest doesn't matter for windows. Just
+	// put it in the same place as on linux.
+	// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#Windows
+	helperNativeManifestDir    = "TorBrowser/Data/Browser/.mozilla/native-messaging-hosts"
+	helperNativeExecutablePath = "TorBrowser/Tor/PluggableTransports/meek-http-helper.exe"
 )
 
 func osSpecificCommandSetup(cmd *exec.Cmd) {
 	// nothing
 }
+
+func installHelperNativeManifest() error {
+	absManifestPath, err := filepath.Abs(filepath.Join(helperNativeManifestDir, nativeAppName+".json"))
+	if err != nil {
+		return err
+	}
+
+	err = writeNativeManifestToFile(helperNativeManifestDir, helperNativeExecutablePath)
+	if err != nil {
+		return err
+	}
+
+	// TODO: Find a way to do this without having to write to the registry.
+	// https://bugs.torproject.org/29347#comment:9
+	// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#Windows
+	k, _, err := registry.CreateKey(
+		registry.CURRENT_USER,
+		`SOFTWARE\Mozilla\NativeMessagingHosts\`+nativeAppName,
+		registry.WRITE,
+	)
+	if err != nil {
+		return err
+	}
+	return k.SetStringValue("", absManifestPath)
+}





More information about the tor-commits mailing list