mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-23 00:01:36 +00:00
Start unifying options and the command-line: booleans
This commit: - Adds a help field to options - Adds a function to generate parser definitions from options - Uses this to migrate all boolean flags over to the new system - Makes all booleans consistently follow the --foo/--not-foo convention There are a number of things left to be done here: - Argparse doesn't give us a nice way to format --foo --not-foo help. Click does, and moving to click is a goal down the track. - For now, we remove all short aliases. I want to re-evaluate these systematically once we have the new structure in place.
This commit is contained in:
parent
67381ae550
commit
f15a628561
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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."
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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")
|
||||
|
@ -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(
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user