diff options
Diffstat (limited to 'testing/mozbase/mozproxy/mozproxy/backends/mitm/desktop.py')
-rw-r--r-- | testing/mozbase/mozproxy/mozproxy/backends/mitm/desktop.py | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/testing/mozbase/mozproxy/mozproxy/backends/mitm/desktop.py b/testing/mozbase/mozproxy/mozproxy/backends/mitm/desktop.py new file mode 100644 index 0000000000..8cb9c496d2 --- /dev/null +++ b/testing/mozbase/mozproxy/mozproxy/backends/mitm/desktop.py @@ -0,0 +1,160 @@ +"""Functions to download, install, setup, and use the mitmproxy playback tool""" +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +import os +import sys + +import mozinfo + +from mozproxy.backends.mitm.mitm import Mitmproxy +from mozproxy.utils import LOG + +# to install mitmproxy certificate into Firefox and turn on/off proxy +POLICIES_CONTENT_ON = """{ + "policies": { + "Certificates": { + "Install": ["%(cert)s"] + }, + "Proxy": { + "Mode": "manual", + "HTTPProxy": "%(host)s:%(port)d", + "SSLProxy": "%(host)s:%(port)d", + "Passthrough": "%(host)s", + "Locked": true + } + } +}""" + +POLICIES_CONTENT_OFF = """{ + "policies": { + "Proxy": { + "Mode": "none", + "Locked": false + } + } +}""" + +# path for mitmproxy certificate, generated auto after mitmdump is started +# on local machine it is 'HOME', however it is different on production machines +try: + DEFAULT_CERT_PATH = os.path.join( + os.getenv("HOME"), ".mitmproxy", "mitmproxy-ca-cert.cer" + ) +except Exception: + DEFAULT_CERT_PATH = os.path.join( + os.getenv("HOMEDRIVE"), + os.getenv("HOMEPATH"), + ".mitmproxy", + "mitmproxy-ca-cert.cer", + ) + +# On Windows, deal with mozilla-build having forward slashes in $HOME: +if os.name == "nt" and "/" in DEFAULT_CERT_PATH: + DEFAULT_CERT_PATH = DEFAULT_CERT_PATH.replace("/", "\\") + + +class MitmproxyDesktop(Mitmproxy): + def setup(self): + """ + Installs certificates. + + For Firefox we need to install the generated mitmproxy CA cert. For + Chromium this is not necessary as it will be started with the + --ignore-certificate-errors cmd line arg. + """ + if not self.config["app"] == "firefox": + return + # install the generated CA certificate into Firefox desktop + self.install_mitmproxy_cert(self.browser_path) + + def install_mitmproxy_cert(self, browser_path): + """Install the CA certificate generated by mitmproxy, into Firefox + 1. Create a dir called 'distribution' in the same directory as the Firefox executable + 2. Create the policies.json file inside that folder; which points to the certificate + location, and turns on the the browser proxy settings + """ + LOG.info("Installing mitmproxy CA certificate into Firefox") + + # browser_path is the exe, we want the folder + self.policies_dir = os.path.dirname(browser_path) + # on macosx we need to remove the last folders 'MacOS' + # and the policies json needs to go in ../Content/Resources/ + if "mac" in self.config["platform"]: + self.policies_dir = os.path.join(self.policies_dir[:-6], "Resources") + # for all platforms the policies json goes in a 'distribution' dir + self.policies_dir = os.path.join(self.policies_dir, "distribution") + + self.cert_path = DEFAULT_CERT_PATH + # for windows only + if mozinfo.os == "win": + self.cert_path = self.cert_path.replace("\\", "\\\\") + + if not os.path.exists(self.policies_dir): + LOG.info("creating folder: %s" % self.policies_dir) + os.makedirs(self.policies_dir) + else: + LOG.info("folder already exists: %s" % self.policies_dir) + + self.write_policies_json( + self.policies_dir, + policies_content=POLICIES_CONTENT_ON + % {"cert": self.cert_path, "host": self.host, "port": self.port}, + ) + + # cannot continue if failed to add CA cert to Firefox, need to check + if not self.is_mitmproxy_cert_installed(): + LOG.error( + "Aborting: failed to install mitmproxy CA cert into Firefox desktop" + ) + self.stop_mitmproxy_playback() + sys.exit() + + def write_policies_json(self, location, policies_content): + policies_file = os.path.join(location, "policies.json") + LOG.info("writing: %s" % policies_file) + + with open(policies_file, "w") as fd: + fd.write(policies_content) + + def read_policies_json(self, location): + policies_file = os.path.join(location, "policies.json") + LOG.info("reading: %s" % policies_file) + + with open(policies_file, "r") as fd: + return fd.read() + + def is_mitmproxy_cert_installed(self): + """Verify mitmxproy CA cert was added to Firefox""" + try: + # read autoconfig file, confirm mitmproxy cert is in there + contents = self.read_policies_json(self.policies_dir) + LOG.info("Firefox policies file contents:") + LOG.info(contents) + if ( + POLICIES_CONTENT_ON + % {"cert": self.cert_path, "host": self.host, "port": self.port} + ) in contents: + LOG.info("Verified mitmproxy CA certificate is installed in Firefox") + else: + return False + except Exception as e: + LOG.info("failed to read Firefox policies file, exeption: %s" % e) + return False + return True + + def stop(self): + LOG.info("MitmproxyDesktop stop!!") + super(MitmproxyDesktop, self).stop() + self.turn_off_browser_proxy() + + def turn_off_browser_proxy(self): + """Turn off the browser proxy that was used for mitmproxy playback. In Firefox + we need to change the autoconfig files to revert the proxy; for Chromium the proxy + was setup on the cmd line, so nothing is required here.""" + if self.config["app"] == "firefox" and self.policies_dir is not None: + LOG.info("Turning off the browser proxy") + + self.write_policies_json( + self.policies_dir, policies_content=POLICIES_CONTENT_OFF + ) |