Skip to content
Snippets Groups Projects
Commit 5b539a2c authored by David Fifield's avatar David Fifield
Browse files

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.
parent 09bde7b8
No related branches found
Tags 0.31-webextension-1
No related merge requests found
......@@ -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)
}
......@@ -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)
}
......@@ -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
......
// 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@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@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
}
......@@ -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)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment