diff --git a/mitmproxy/options.py b/mitmproxy/options.py index 160093166..1d879ac81 100644 --- a/mitmproxy/options.py +++ b/mitmproxy/options.py @@ -23,20 +23,50 @@ DEFAULT_CLIENT_CIPHERS = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA class Options(optmanager.OptManager): def __init__(self, **kwargs) -> None: super().__init__() - self.add_option("onboarding", True, bool) + self.add_option( + "onboarding", True, bool, + "Toggle the mitmproxy onboarding app." + ) self.add_option("onboarding_host", APP_HOST, str) self.add_option("onboarding_port", APP_PORT, int) - self.add_option("anticache", False, bool) - self.add_option("anticomp", False, bool) + self.add_option( + "anticache", False, bool, + """ + Strip out request headers that might cause the server to return + 304-not-modified. + """ + ) + self.add_option( + "anticomp", False, bool, + "Try to convince servers to send us un-compressed data." + ) self.add_option("client_replay", [], Sequence[str]) - self.add_option("replay_kill_extra", False, bool) - self.add_option("keepserving", True, bool) - self.add_option("no_server", False, bool) - self.add_option("server_replay_nopop", False, bool) - self.add_option("refresh_server_playback", True, bool) + self.add_option( + "replay_kill_extra", False, bool, + "Kill extra requests during replay." + ) + self.add_option( + "keepserving", True, bool, + "Continue serving after client playback or file read." + ) + self.add_option( + "no_server", False, bool, + "Don't start a proxy server." + ) + self.add_option( + "server_replay_nopop", False, bool, + "Disable response pop from response flow. " + "This makes it possible to replay same response multiple times." + ) + self.add_option( + "refresh_server_playback", True, bool, + ) self.add_option("rfile", None, Optional[str]) self.add_option("scripts", [], Sequence[str]) - self.add_option("showhost", False, bool) + self.add_option( + "showhost", False, bool, + "Use the Host header to construct URLs for display." + ) self.add_option("replacements", [], Sequence[Union[Tuple[str, str, str], str]]) self.add_option("replacement_files", [], Sequence[Union[Tuple[str, str, str], str]]) self.add_option("server_replay_use_headers", [], Sequence[str]) @@ -49,16 +79,30 @@ class Options(optmanager.OptManager): self.add_option("default_contentview", "auto", str) self.add_option("streamfile", None, Optional[str]) self.add_option("streamfile_append", False, bool) - self.add_option("server_replay_ignore_content", False, bool) + self.add_option( + "server_replay_ignore_content", False, bool, + "Ignore request's content while searching for a saved flow to replay." + ) self.add_option("server_replay_ignore_params", [], Sequence[str]) self.add_option("server_replay_ignore_payload_params", [], Sequence[str]) - self.add_option("server_replay_ignore_host", False, bool) + self.add_option( + "server_replay_ignore_host", False, bool, + "Ignore request's destination host while searching for a saved" + " flow to replay" + ) # Proxy options - self.add_option("auth_nonanonymous", False, bool) + self.add_option( + "auth_nonanonymous", False, bool, + "Allow access to any user long as a credentials are specified." + ) self.add_option("auth_singleuser", None, Optional[str]) self.add_option("auth_htpasswd", None, Optional[str]) - self.add_option("add_upstream_certs_to_client_chain", False, bool) + self.add_option( + "add_upstream_certs_to_client_chain", False, bool, + "Add all certificates of the upstream server to the certificate chain " + "that will be served to the proxy client, as extras." + ) self.add_option("body_size_limit", None, Optional[int]) self.add_option("cadir", CA_DIR, str) self.add_option("certs", [], Sequence[Tuple[str, str]]) @@ -70,20 +114,51 @@ class Options(optmanager.OptManager): self.add_option("listen_port", LISTEN_PORT, int) self.add_option("upstream_bind_address", "", str) self.add_option("mode", "regular", str) - self.add_option("no_upstream_cert", False, bool) - self.add_option("keep_host_header", False, bool) + self.add_option( + "upstream_cert", True, bool, + "Connect to upstream server to look up certificate details." + ) + self.add_option( + "keep_host_header", False, bool, + "Reverse Proxy: Keep the original host header instead of rewriting it" + " to the reverse proxy target." + ) - self.add_option("http2", True, bool) - self.add_option("http2_priority", False, bool) - self.add_option("websocket", True, bool) - self.add_option("rawtcp", False, bool) + self.add_option( + "http2", True, bool, + "Enable/disable HTTP/2 support. " + "HTTP/2 support is enabled by default.", + ) + self.add_option( + "http2_priority", False, bool, + "Enable/disable PRIORITY forwarding for HTTP/2 connections. " + "PRIORITY forwarding is disabled by default, " + "because some webservers fail to implement the RFC properly.", + ) + self.add_option( + "websocket", True, bool, + "Enable/disable WebSocket support. " + "WebSocket support is enabled by default.", + ) + self.add_option( + "rawtcp", False, bool, + "Enable/disable experimental raw TCP support. " + "Disabled by default. " + ) - self.add_option("spoof_source_address", False, bool) + self.add_option( + "spoof_source_address", False, bool, + "Use the client's IP for server-side connections. " + "Combine with --upstream-bind-address to spoof a fixed source address." + ) self.add_option("upstream_server", None, Optional[str]) self.add_option("upstream_auth", None, Optional[str]) self.add_option("ssl_version_client", "secure", str) self.add_option("ssl_version_server", "secure", str) - self.add_option("ssl_insecure", False, bool) + self.add_option( + "ssl_insecure", False, bool, + "Do not verify upstream server SSL/TLS certificates." + ) self.add_option("ssl_verify_upstream_trusted_cadir", None, Optional[str]) self.add_option("ssl_verify_upstream_trusted_ca", None, Optional[str]) self.add_option("tcp_hosts", [], Sequence[str]) @@ -91,19 +166,39 @@ class Options(optmanager.OptManager): self.add_option("intercept", None, Optional[str]) # Console options - self.add_option("console_eventlog", False, bool) - self.add_option("console_focus_follow", False, bool) + self.add_option( + "console_eventlog", False, bool, + help="Show event log." + ) + self.add_option( + "console_focus_follow", False, bool, + "Focus follows new flows." + ) self.add_option("console_palette", "dark", Optional[str]) - self.add_option("console_palette_transparent", False, bool) - self.add_option("console_no_mouse", False, bool) + self.add_option( + "console_palette_transparent", False, bool, + "Set transparent background for palette." + ) + self.add_option( + "console_mouse", True, bool, + "Console mouse interaction." + ) self.add_option("console_order", None, Optional[str]) - self.add_option("console_order_reversed", False, bool) + self.add_option( + "console_order_reversed", False, bool, + ) self.add_option("filter", None, Optional[str]) # Web options - self.add_option("web_open_browser", True, bool) - self.add_option("web_debug", False, bool) + self.add_option( + "web_open_browser", True, bool, + "Start a browser" + ) + self.add_option( + "web_debug", False, bool, + "Mitmweb debugging" + ) self.add_option("web_port", 8081, int) self.add_option("web_iface", "127.0.0.1", str) diff --git a/mitmproxy/optmanager.py b/mitmproxy/optmanager.py index 4b5a710e0..240e36425 100644 --- a/mitmproxy/optmanager.py +++ b/mitmproxy/optmanager.py @@ -21,19 +21,21 @@ unset = object() class _Option: - __slots__ = ("name", "typespec", "value", "_default") + __slots__ = ("name", "typespec", "value", "_default", "help") def __init__( self, name: str, default: typing.Any, - typespec: typing.Type + typespec: typing.Type, + help: typing.Optional[str] ) -> None: typecheck.check_type(name, default, typespec) self.name = name self._default = default self.typespec = typespec self.value = unset + self.help = help def __repr__(self): return "{value} [{type}]".format(value=self.current(), type=self.typespec) @@ -66,7 +68,7 @@ class _Option: return True def __deepcopy__(self, _): - o = _Option(self.name, self.default, self.typespec) + o = _Option(self.name, self.default, self.typespec, self.help) if self.has_changed(): o.value = self.current() return o @@ -91,10 +93,16 @@ class OptManager: self.__dict__["changed"] = blinker.Signal() self.__dict__["errored"] = blinker.Signal() - def add_option(self, name: str, default: typing.Any, typespec: typing.Type) -> None: + def add_option( + self, + name: str, + default: typing.Any, + typespec: typing.Type, + help: str = None + ) -> None: if name in self._options: raise ValueError("Option %s already exists" % name) - self._options[name] = _Option(name, default, typespec) + self._options[name] = _Option(name, default, typespec, help) @contextlib.contextmanager def rollback(self, updated): @@ -303,3 +311,24 @@ class OptManager: cls=type(self).__name__, options=options ) + + def make_parser(self, parser, option): + o = self._options[option] + f = option.replace("_", "-") + if o.typespec == bool: + g = parser.add_mutually_exclusive_group(required=False) + g.add_argument( + "--%s" % f, + action="store_true", + dest=option, + help=o.help + ) + g.add_argument( + "--no-%s" % f, + action="store_false", + dest=option, + help=o.help + ) + parser.set_defaults(**{option: o.default}) + else: + raise ValueError("Unsupported option type: %s", o.typespec) diff --git a/mitmproxy/proxy/protocol/tls.py b/mitmproxy/proxy/protocol/tls.py index 7d15130f8..103d96cce 100644 --- a/mitmproxy/proxy/protocol/tls.py +++ b/mitmproxy/proxy/protocol/tls.py @@ -358,7 +358,7 @@ class TlsLayer(base.Layer): # 2.5 The client did not sent a SNI value, we don't know the certificate subject. client_tls_requires_server_connection = ( self._server_tls and - not self.config.options.no_upstream_cert and + self.config.options.upstream_cert and ( self.config.options.add_upstream_certs_to_client_chain or self._client_tls and ( @@ -574,7 +574,7 @@ class TlsLayer(base.Layer): use_upstream_cert = ( self.server_conn and self.server_conn.tls_established and - (not self.config.options.no_upstream_cert) + self.config.options.upstream_cert ) if use_upstream_cert: upstream_cert = self.server_conn.cert diff --git a/mitmproxy/tools/cmdline.py b/mitmproxy/tools/cmdline.py index 11558cc3a..41f4cedb0 100644 --- a/mitmproxy/tools/cmdline.py +++ b/mitmproxy/tools/cmdline.py @@ -85,7 +85,7 @@ def get_common_options(args): "are mutually exclusive. Read the docs on proxy modes " "to understand why." ) - if args.add_upstream_certs_to_client_chain and args.no_upstream_cert: + if args.add_upstream_certs_to_client_chain and not args.upstream_cert: raise exceptions.OptionsError( "The no-upstream-cert and add-upstream-certs-to-client-chain " "options are mutually exclusive. If no-upstream-cert is enabled " @@ -106,7 +106,7 @@ def get_common_options(args): client_replay=args.client_replay, replay_kill_extra=args.replay_kill_extra, no_server=args.no_server, - refresh_server_playback=not args.norefresh, + refresh_server_playback=args.refresh_server_playback, server_replay_use_headers=args.server_replay_use_headers, rfile=args.rfile, replacements=args.replacements, @@ -143,7 +143,7 @@ def get_common_options(args): listen_port = args.port, upstream_bind_address = args.upstream_bind_address, mode = mode, - no_upstream_cert = args.no_upstream_cert, + upstream_cert = args.upstream_cert, spoof_source_address = args.spoof_source_address, http2 = args.http2, @@ -162,7 +162,7 @@ def get_common_options(args): ) -def basic_options(parser): +def basic_options(parser, opts): parser.add_argument( '--version', action='store_true', @@ -174,24 +174,13 @@ def basic_options(parser): help="show program's short version number and exit", version=version.VERSION ) - parser.add_argument( - "--anticache", - action="store_true", dest="anticache", - help=""" - Strip out request headers that might cause the server to return - 304-not-modified. - """ - ) + opts.make_parser(parser, "anticache") parser.add_argument( "--cadir", action="store", type=str, dest="cadir", help="Location of the default mitmproxy CA files. (%s)" % options.CA_DIR ) - parser.add_argument( - "--host", - action="store_true", dest="showhost", - help="Use the Host header to construct URLs for display." - ) + opts.make_parser(parser, "showhost") parser.add_argument( "-q", "--quiet", action="store_true", dest="quiet", @@ -239,11 +228,7 @@ def basic_options(parser): action="store", dest="streamfile", type=lambda f: (f, "a"), help="Append flows to file." ) - parser.add_argument( - "-z", "--anticomp", - action="store_true", dest="anticomp", - help="Try to convince servers to send us un-compressed data." - ) + opts.make_parser(parser, "anticomp") parser.add_argument( "-Z", "--body-size-limit", action="store", dest="body_size_limit", @@ -263,7 +248,7 @@ def basic_options(parser): ) -def proxy_modes(parser): +def proxy_modes(parser, opts): group = parser.add_argument_group("Proxy Modes") group.add_argument( "-R", "--reverse", @@ -296,7 +281,7 @@ def proxy_modes(parser): ) -def proxy_options(parser): +def proxy_options(parser, opts): group = parser.add_argument_group("Proxy Options") group.add_argument( "-b", "--bind-address", @@ -326,11 +311,7 @@ def proxy_options(parser): communication contents are printed to the log in verbose mode. """ ) - group.add_argument( - "-n", "--no-server", - action="store_true", dest="no_server", - help="Don't start a proxy server." - ) + opts.make_parser(group, "no_server") group.add_argument( "-p", "--port", action="store", type=int, dest="port", @@ -338,26 +319,11 @@ def proxy_options(parser): ) http2 = group.add_mutually_exclusive_group() - http2.add_argument("--no-http2", action="store_false", dest="http2") - http2.add_argument("--http2", action="store_true", dest="http2", - help="Explicitly enable/disable HTTP/2 support. " - "HTTP/2 support is enabled by default.", - ) - - http2_priority = group.add_mutually_exclusive_group() - http2_priority.add_argument("--http2-priority", action="store_true", dest="http2_priority") - http2_priority.add_argument("--no-http2-priority", action="store_false", dest="http2_priority", - help="Explicitly enable/disable PRIORITY forwarding for HTTP/2 connections. " - "PRIORITY forwarding is disabled by default, " - "because some webservers fail at implementing the RFC properly.", - ) + opts.make_parser(http2, "http2") + opts.make_parser(http2, "http2_priority") websocket = group.add_mutually_exclusive_group() - websocket.add_argument("--no-websocket", action="store_false", dest="websocket") - websocket.add_argument("--websocket", action="store_true", dest="websocket", - help="Explicitly enable/disable WebSocket support. " - "WebSocket support is enabled by default.", - ) + opts.make_parser(websocket, "websocket") parser.add_argument( "--upstream-auth", @@ -369,33 +335,18 @@ def proxy_options(parser): """ ) - rawtcp = group.add_mutually_exclusive_group() - rawtcp.add_argument("--raw-tcp", action="store_true", dest="rawtcp") - rawtcp.add_argument("--no-raw-tcp", action="store_false", dest="rawtcp", - help="Explicitly enable/disable experimental raw tcp support. " - "Disabled by default. " - "Default value will change in a future version." - ) + opts.make_parser(group, "rawtcp") - group.add_argument( - "--spoof-source-address", - action="store_true", dest="spoof_source_address", - help="Use the client's IP for server-side connections. " - "Combine with --upstream-bind-address to spoof a fixed source address." - ) + opts.make_parser(group, "spoof_source_address") group.add_argument( "--upstream-bind-address", action="store", type=str, dest="upstream_bind_address", help="Address to bind upstream requests to (defaults to none)" ) - group.add_argument( - "--keep-host-header", - action="store_true", dest="keep_host_header", - help="Reverse Proxy: Keep the original host header instead of rewriting it to the reverse proxy target." - ) + opts.make_parser(group, "keep_host_header") -def proxy_ssl_options(parser): +def proxy_ssl_options(parser, opts): # TODO: Agree to consistently either use "upstream" or "server". group = parser.add_argument_group("SSL") group.add_argument( @@ -425,22 +376,9 @@ def proxy_ssl_options(parser): type=str, dest="clientcerts", help="Client certificate file or directory." ) - group.add_argument( - "--no-upstream-cert", - action="store_true", dest="no_upstream_cert", - help="Don't connect to upstream server to look up certificate details." - ) - group.add_argument( - "--add-upstream-certs-to-client-chain", - action="store_true", dest="add_upstream_certs_to_client_chain", - help="Add all certificates of the upstream server to the certificate chain " - "that will be served to the proxy client, as extras." - ) - group.add_argument( - "--insecure", - action="store_true", dest="ssl_insecure", - help="Do not verify upstream server SSL/TLS certificates." - ) + opts.make_parser(group, "upstream_cert") + opts.make_parser(group, "add_upstream_certs_to_client_chain") + opts.make_parser(group, "ssl_insecure") group.add_argument( "--upstream-trusted-cadir", action="store", dest="ssl_verify_upstream_trusted_cadir", @@ -468,13 +406,9 @@ def proxy_ssl_options(parser): ) -def onboarding_app(parser): +def onboarding_app(parser, opts): group = parser.add_argument_group("Onboarding App") - group.add_argument( - "--no-onboarding", - action="store_false", dest="onboarding", - help="Disable the mitmproxy onboarding app." - ) + opts.make_parser(parser, "onboarding") group.add_argument( "--onboarding-host", action="store", dest="onboarding_host", @@ -494,7 +428,7 @@ def onboarding_app(parser): ) -def client_replay(parser): +def client_replay(parser, opts): group = parser.add_argument_group("Client Replay") group.add_argument( "-c", "--client-replay", @@ -503,46 +437,24 @@ def client_replay(parser): ) -def server_replay(parser): +def server_replay(parser, opts): group = parser.add_argument_group("Server Replay") group.add_argument( "-S", "--server-replay", action="append", dest="server_replay", metavar="PATH", help="Replay server responses from a saved file." ) - group.add_argument( - "-k", "--replay-kill-extra", - action="store_true", dest="replay_kill_extra", - help="Kill extra requests during replay." - ) + opts.make_parser(parser, "replay_kill_extra") group.add_argument( "--server-replay-use-header", action="append", dest="server_replay_use_headers", type=str, help="Request headers to be considered during replay. " "Can be passed multiple times." ) - group.add_argument( - "--norefresh", - action="store_true", dest="norefresh", - help=""" - Disable response refresh, which updates times in cookies and headers - for replayed responses. - """ - ) - group.add_argument( - "--no-pop", - action="store_true", dest="server_replay_nopop", - help="Disable response pop from response flow. " - "This makes it possible to replay same response multiple times." - ) + opts.make_parser(group, "refresh_server_playback") + opts.make_parser(group, "server_replay_nopop") payload = group.add_mutually_exclusive_group() - payload.add_argument( - "--replay-ignore-content", - action="store_true", dest="server_replay_ignore_content", - help=""" - Ignore request's content while searching for a saved flow to replay - """ - ) + opts.make_parser(payload, "server_replay_ignore_content") payload.add_argument( "--replay-ignore-payload-param", action="append", dest="server_replay_ignore_payload_params", type=str, @@ -561,14 +473,10 @@ def server_replay(parser): to replay. Can be passed multiple times. """ ) - group.add_argument( - "--replay-ignore-host", - action="store_true", - dest="server_replay_ignore_host", - help="Ignore request's destination host while searching for a saved flow to replay") + opts.make_parser(parser, "server_replay_ignore_host") -def replacements(parser): +def replacements(parser, opts): group = parser.add_argument_group( "Replacements", """ @@ -594,7 +502,7 @@ def replacements(parser): ) -def set_headers(parser): +def set_headers(parser, opts): group = parser.add_argument_group( "Set Headers", """ @@ -611,7 +519,7 @@ def set_headers(parser): ) -def proxy_authentication(parser): +def proxy_authentication(parser, opts): group = parser.add_argument_group( "Proxy Authentication", """ @@ -619,12 +527,7 @@ def proxy_authentication(parser): used for authenticating them. """ ).add_mutually_exclusive_group() - group.add_argument( - "--nonanonymous", - action="store_true", dest="auth_nonanonymous", - help="Allow access to any user long as a credentials are specified." - ) - + opts.make_parser(group, "auth_nonanonymous") group.add_argument( "--singleuser", action="store", dest="auth_singleuser", type=str, @@ -642,7 +545,7 @@ def proxy_authentication(parser): ) -def common_options(parser): +def common_options(parser, opts): parser.add_argument( "--conf", type=str, dest="conf", default=CONFIG_PATH, @@ -651,58 +554,41 @@ def common_options(parser): Configuration file """ ) - - basic_options(parser) - proxy_modes(parser) - proxy_options(parser) - proxy_ssl_options(parser) - onboarding_app(parser) - client_replay(parser) - server_replay(parser) - replacements(parser) - set_headers(parser) - proxy_authentication(parser) + basic_options(parser, opts) + proxy_modes(parser, opts) + proxy_options(parser, opts) + proxy_ssl_options(parser, opts) + onboarding_app(parser, opts) + client_replay(parser, opts) + server_replay(parser, opts) + replacements(parser, opts) + set_headers(parser, opts) + proxy_authentication(parser, opts) -def mitmproxy(): +def mitmproxy(opts): # Don't import mitmproxy.tools.console for mitmdump, urwid is not available # on all platforms. from .console import palettes parser = argparse.ArgumentParser(usage="%(prog)s [options]") - common_options(parser) + common_options(parser, opts) parser.add_argument( "--palette", type=str, action="store", dest="console_palette", choices=sorted(palettes.palettes.keys()), help="Select color palette: " + ", ".join(palettes.palettes.keys()) ) - parser.add_argument( - "--palette-transparent", - action="store_true", dest="console_palette_transparent", - help="Set transparent background for palette." - ) - parser.add_argument( - "-e", "--eventlog", - action="store_true", dest="console_eventlog", - help="Show event log." - ) - parser.add_argument( - "--follow", - action="store_true", dest="console_focus_follow", - help="Focus follows new flows." - ) + opts.make_parser(parser, "console_palette_transparent") + opts.make_parser(parser, "console_eventlog") + opts.make_parser(parser, "console_focus_follow") parser.add_argument( "--order", type=str, dest="console_order", choices=[o[1] for o in view.orders], help="Flow sort order." ) - parser.add_argument( - "--no-mouse", - action="store_true", dest="console_no_mouse", - help="Disable mouse interaction." - ) + opts.make_parser(parser, "console_mouse") group = parser.add_argument_group( "Filters", "See help in mitmproxy for filter expression syntax." @@ -720,18 +606,11 @@ def mitmproxy(): return parser -def mitmdump(): +def mitmdump(opts): parser = argparse.ArgumentParser(usage="%(prog)s [options] [filter]") - common_options(parser) - parser.add_argument( - "--keepserving", - action="store_true", dest="keepserving", - help=""" - Continue serving after client playback or file read. We exit by - default. - """ - ) + common_options(parser, opts) + opts.make_parser(parser, "keepserving") parser.add_argument( "-d", "--detail", action="count", dest="flow_detail", @@ -748,15 +627,11 @@ def mitmdump(): return parser -def mitmweb(): +def mitmweb(opts): parser = argparse.ArgumentParser(usage="%(prog)s [options]") group = parser.add_argument_group("Mitmweb") - group.add_argument( - "--no-browser", - action="store_false", dest="web_open_browser", - help="Don't start a browser" - ) + opts.make_parser(group, "web_open_browser") group.add_argument( "--web-port", action="store", type=int, dest="web_port", @@ -769,13 +644,9 @@ def mitmweb(): metavar="IFACE", help="Mitmweb interface." ) - group.add_argument( - "--web-debug", - action="store_true", dest="web_debug", - help="Turn on mitmweb debugging" - ) + opts.make_parser(group, "web_debug") - common_options(parser) + common_options(parser, opts) group = parser.add_argument_group( "Filters", "See help in mitmproxy for filter expression syntax." diff --git a/mitmproxy/tools/console/master.py b/mitmproxy/tools/console/master.py index d68dc93c8..e75105cfc 100644 --- a/mitmproxy/tools/console/master.py +++ b/mitmproxy/tools/console/master.py @@ -252,7 +252,7 @@ class ConsoleMaster(master.Master): self.loop = urwid.MainLoop( urwid.SolidFill("x"), screen = self.ui, - handle_mouse = not self.options.console_no_mouse, + handle_mouse = self.options.console_mouse, ) self.ab = statusbar.ActionBar() diff --git a/mitmproxy/tools/console/options.py b/mitmproxy/tools/console/options.py index 4115bd180..33e3ec38e 100644 --- a/mitmproxy/tools/console/options.py +++ b/mitmproxy/tools/console/options.py @@ -90,10 +90,10 @@ class Options(urwid.WidgetWrap): select.Heading("Network"), select.Option( - "No Upstream Certs", + "Upstream Certs", "U", - checker("no_upstream_cert", master.options), - master.options.toggler("no_upstream_cert") + checker("upstream_cert", master.options), + master.options.toggler("upstream_cert") ), select.Option( "TCP Proxying", diff --git a/mitmproxy/tools/console/statusbar.py b/mitmproxy/tools/console/statusbar.py index d90d932be..a5611b28c 100644 --- a/mitmproxy/tools/console/statusbar.py +++ b/mitmproxy/tools/console/statusbar.py @@ -220,7 +220,7 @@ class StatusBar(urwid.WidgetWrap): opts.append("norefresh") if self.master.options.replay_kill_extra: opts.append("killextra") - if self.master.options.no_upstream_cert: + if not self.master.options.upstream_cert: opts.append("no-upstream-cert") if self.master.options.console_focus_follow: opts.append("following") diff --git a/mitmproxy/tools/main.py b/mitmproxy/tools/main.py index ce78cd13f..c0293f28f 100644 --- a/mitmproxy/tools/main.py +++ b/mitmproxy/tools/main.py @@ -61,11 +61,11 @@ def mitmproxy(args=None): # pragma: no cover version_check.check_pyopenssl_version() assert_utf8_env() - parser = cmdline.mitmproxy() + console_options = options.Options() + parser = cmdline.mitmproxy(console_options) args = parser.parse_args(args) try: - console_options = options.Options() console_options.load_paths(args.conf) console_options.merge(cmdline.get_common_options(args)) console_options.merge( @@ -74,7 +74,7 @@ def mitmproxy(args=None): # pragma: no cover console_palette_transparent = args.console_palette_transparent, console_eventlog = args.console_eventlog, console_focus_follow = args.console_focus_follow, - console_no_mouse = args.console_no_mouse, + console_mouse = args.console_mouse, console_order = args.console_order, filter = args.filter, @@ -98,14 +98,14 @@ def mitmdump(args=None): # pragma: no cover version_check.check_pyopenssl_version() - parser = cmdline.mitmdump() + dump_options = options.Options() + parser = cmdline.mitmdump(dump_options) args = parser.parse_args(args) if args.quiet: args.flow_detail = 0 master = None try: - dump_options = options.Options() dump_options.load_paths(args.conf) dump_options.merge(cmdline.get_common_options(args)) dump_options.merge( @@ -139,12 +139,11 @@ def mitmweb(args=None): # pragma: no cover version_check.check_pyopenssl_version() - parser = cmdline.mitmweb() - + web_options = options.Options() + parser = cmdline.mitmweb(web_options) args = parser.parse_args(args) try: - web_options = options.Options() web_options.load_paths(args.conf) web_options.merge(cmdline.get_common_options(args)) web_options.merge( diff --git a/mitmproxy/tools/web/app.py b/mitmproxy/tools/web/app.py index 35b549ee4..eddaa3e10 100644 --- a/mitmproxy/tools/web/app.py +++ b/mitmproxy/tools/web/app.py @@ -408,7 +408,7 @@ class Settings(RequestHandler): mode=str(self.master.options.mode), intercept=self.master.options.intercept, showhost=self.master.options.showhost, - no_upstream_cert=self.master.options.no_upstream_cert, + upstream_cert=self.master.options.upstream_cert, rawtcp=self.master.options.rawtcp, http2=self.master.options.http2, websocket=self.master.options.websocket, @@ -425,7 +425,7 @@ class Settings(RequestHandler): def put(self): update = self.json option_whitelist = { - "intercept", "showhost", "no_upstream_cert", + "intercept", "showhost", "upstream_cert", "rawtcp", "http2", "websocket", "anticache", "anticomp", "stickycookie", "stickyauth", "stream_large_bodies" } diff --git a/test/mitmproxy/proxy/protocol/test_http2.py b/test/mitmproxy/proxy/protocol/test_http2.py index 871d02fe6..770c65501 100644 --- a/test/mitmproxy/proxy/protocol/test_http2.py +++ b/test/mitmproxy/proxy/protocol/test_http2.py @@ -100,7 +100,7 @@ class _Http2TestBase: def get_options(cls): opts = options.Options( listen_port=0, - no_upstream_cert=False, + upstream_cert=True, ssl_insecure=True ) opts.cadir = os.path.join(tempfile.gettempdir(), "mitmproxy") diff --git a/test/mitmproxy/proxy/protocol/test_websocket.py b/test/mitmproxy/proxy/protocol/test_websocket.py index bac0e527d..486e9d64c 100644 --- a/test/mitmproxy/proxy/protocol/test_websocket.py +++ b/test/mitmproxy/proxy/protocol/test_websocket.py @@ -64,7 +64,7 @@ class _WebSocketTestBase: def get_options(cls): opts = options.Options( listen_port=0, - no_upstream_cert=False, + upstream_cert=True, ssl_insecure=True, websocket=True, ) diff --git a/test/mitmproxy/proxy/test_server.py b/test/mitmproxy/proxy/test_server.py index 56b09b9a8..eb40dd143 100644 --- a/test/mitmproxy/proxy/test_server.py +++ b/test/mitmproxy/proxy/test_server.py @@ -870,11 +870,11 @@ class TestServerConnect(tservers.HTTPProxyTest): @classmethod def get_options(cls): opts = tservers.HTTPProxyTest.get_options() - opts.no_upstream_cert = True + opts.upstream_cert = False return opts def test_unnecessary_serverconnect(self): - """A replayed/fake response with no_upstream_cert should not connect to an upstream server""" + """A replayed/fake response with no upstream_cert should not connect to an upstream server""" assert self.pathod("200").status_code == 200 for msg in self.proxy.tmaster.tlog: assert "serverconnect" not in msg diff --git a/test/mitmproxy/test_optmanager.py b/test/mitmproxy/test_optmanager.py index 3fba304a3..44c757af0 100644 --- a/test/mitmproxy/test_optmanager.py +++ b/test/mitmproxy/test_optmanager.py @@ -252,14 +252,14 @@ def test_merge(): def test_option(): - o = optmanager._Option("test", 1, int) + o = optmanager._Option("test", 1, int, None) assert o.current() == 1 with pytest.raises(TypeError): o.set("foo") with pytest.raises(TypeError): - optmanager._Option("test", 1, str) + optmanager._Option("test", 1, str, None) - o2 = optmanager._Option("test", 1, int) + o2 = optmanager._Option("test", 1, int, None) assert o2 == o o2.set(5) assert o2 != o diff --git a/test/mitmproxy/test_proxy.py b/test/mitmproxy/test_proxy.py index 37cec57ac..6e3608754 100644 --- a/test/mitmproxy/test_proxy.py +++ b/test/mitmproxy/test_proxy.py @@ -30,9 +30,9 @@ class TestProcessProxyOptions: def p(self, *args): parser = MockParser() - cmdline.common_options(parser) - args = parser.parse_args(args=args) opts = options.Options() + cmdline.common_options(parser, opts) + args = parser.parse_args(args=args) opts.merge(cmdline.get_common_options(args)) pconf = config.ProxyConfig(opts) return parser, pconf @@ -91,7 +91,7 @@ class TestProcessProxyOptions: self.p("--cert", "nonexistent") def test_insecure(self): - p = self.assert_noerr("--insecure") + p = self.assert_noerr("--ssl-insecure") assert p.openssl_verification_mode_server == SSL.VERIFY_NONE def test_upstream_trusted_cadir(self): diff --git a/test/mitmproxy/tools/test_cmdline.py b/test/mitmproxy/tools/test_cmdline.py index 96d5ae312..b9f9d00d7 100644 --- a/test/mitmproxy/tools/test_cmdline.py +++ b/test/mitmproxy/tools/test_cmdline.py @@ -1,31 +1,36 @@ import argparse from mitmproxy.tools import cmdline +from mitmproxy import options def test_common(): parser = argparse.ArgumentParser() - cmdline.common_options(parser) - opts = parser.parse_args(args=[]) + opts = options.Options() + cmdline.common_options(parser, opts) + args = parser.parse_args(args=[]) - assert cmdline.get_common_options(opts) + assert cmdline.get_common_options(args) - opts.stickycookie_filt = "foo" - opts.stickyauth_filt = "foo" - v = cmdline.get_common_options(opts) + args.stickycookie_filt = "foo" + args.stickyauth_filt = "foo" + v = cmdline.get_common_options(args) assert v["stickycookie"] == "foo" assert v["stickyauth"] == "foo" def test_mitmproxy(): - ap = cmdline.mitmproxy() + opts = options.Options() + ap = cmdline.mitmproxy(opts) assert ap def test_mitmdump(): - ap = cmdline.mitmdump() + opts = options.Options() + ap = cmdline.mitmdump(opts) assert ap def test_mitmweb(): - ap = cmdline.mitmweb() + opts = options.Options() + ap = cmdline.mitmweb(opts) assert ap diff --git a/tox.ini b/tox.ini index 4994b1191..a9904e876 100644 --- a/tox.ini +++ b/tox.ini @@ -30,6 +30,7 @@ commands = mypy --ignore-missing-imports --follow-imports=skip \ mitmproxy/addons/ \ mitmproxy/addonmanager.py \ + mitmproxy/optmanager.py \ mitmproxy/proxy/protocol/ \ mitmproxy/log.py \ mitmproxy/tools/dump.py \