commit c7b99db18bb4f60c5221bf62b7bee3eb0b558434 Author: David Fifield david@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/Nativ... + 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/Nativ... + 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/Nativ... + 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/Nativ... + +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/WebEx... + addOnID = "meek-http-helper@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/Nativ... +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@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/Nativ... + 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/Nativ... + k, _, err := registry.CreateKey( + registry.CURRENT_USER, + `SOFTWARE\Mozilla\NativeMessagingHosts`+nativeAppName, + registry.WRITE, + ) + if err != nil { + return err + } + return k.SetStringValue("", absManifestPath) +}
tor-commits@lists.torproject.org