commit 5b539a2c5f2a8474cee3dc2c2312ad365bdb1cca
Author: David Fifield <da...@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 0c9910f..ab1ed9c 100644
--- a/meek-client-torbrowser/meek-client-torbrowser.go
+++ b/meek-client-torbrowser/meek-client-torbrowser.go
@@ -226,6 +226,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-hel...@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-hel...@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)
+}

_______________________________________________
tor-commits mailing list
tor-commits@lists.torproject.org
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits

Reply via email to