[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