Files
baijiahao_data_crawl/venv/Lib/site-packages/mitmproxy/tools/web/webaddons.py
“shengyudong” 322ac74336 2025-12-25 upload
2025-12-25 11:16:59 +08:00

152 lines
5.1 KiB
Python

from __future__ import annotations
import hmac
import logging
import secrets
import webbrowser
from collections.abc import Sequence
from typing import TYPE_CHECKING
import argon2
from mitmproxy import ctx
from mitmproxy import exceptions
from mitmproxy.tools.web.web_columns import AVAILABLE_WEB_COLUMNS
if TYPE_CHECKING:
from mitmproxy.tools.web.master import WebMaster
logger = logging.getLogger(__name__)
class WebAuth:
_password: str
_hasher: argon2.PasswordHasher
def __init__(self):
self._password = secrets.token_hex(16)
self._hasher = argon2.PasswordHasher()
def load(self, loader):
loader.add_option(
"web_password",
str,
"",
"Password to protect the mitmweb user interface. "
"Values starting with `$` are interpreted as an argon2 hash, "
"everything else is considered a plaintext password. "
"If no password is provided, a random token is generated on startup."
"For automated calls, you can pass the password as token query parameter"
"or as `Authorization: Bearer ...` header.",
)
def configure(self, updated) -> None:
if "web_password" in updated:
if ctx.options.web_password.startswith("$"):
try:
argon2.extract_parameters(ctx.options.web_password)
except argon2.exceptions.InvalidHashError:
raise exceptions.OptionsError(
"`web_password` starts with `$`, but it's not a valid argon2 hash."
)
elif ctx.options.web_password:
logger.warning(
"Using a plaintext password to protect the mitmweb user interface. "
"Consider using an argon2 hash for `web_password` instead."
)
self._password = ctx.options.web_password or secrets.token_hex(16)
@property
def web_url(self) -> str:
if ctx.options.web_password:
auth = "" # We don't want to print plaintext passwords (and it doesn't work for argon2 anyhow).
else:
auth = f"?token={self._password}"
web_host = ctx.options.web_host
if ":" in web_host: # ipv6
web_host = f"[{web_host}]"
# noinspection HttpUrlsUsage
return f"http://{web_host}:{ctx.options.web_port}/{auth}"
@staticmethod
def auth_cookie_name() -> str:
return f"mitmproxy-auth-{ctx.options.web_port}"
def is_valid_password(self, password: str) -> bool:
if self._password.startswith("$"):
try:
return self._hasher.verify(self._password, password)
except argon2.exceptions.VerificationError:
return False
else:
return hmac.compare_digest(
self._password,
password,
)
class WebAddon:
def load(self, loader):
loader.add_option("web_open_browser", bool, True, "Start a browser.")
loader.add_option("web_debug", bool, False, "Enable mitmweb debugging.")
loader.add_option("web_port", int, 8081, "Web UI port.")
loader.add_option("web_host", str, "127.0.0.1", "Web UI host.")
loader.add_option(
"web_columns",
Sequence[str],
["tls", "icon", "path", "method", "status", "size", "time"],
f"Columns to show in the flow list. Can be one of the following: {', '.join(AVAILABLE_WEB_COLUMNS)}",
)
def running(self):
if hasattr(ctx.options, "web_open_browser") and ctx.options.web_open_browser:
master: WebMaster = ctx.master # type: ignore
success = open_browser(master.web_url)
if not success:
logger.info(
f"No web browser found. Please open a browser and point it to {master.web_url}",
)
if not success and not ctx.options.web_password:
logger.info(
f"You can configure a fixed authentication token by setting the `web_password` option "
f"(https://docs.mitmproxy.org/stable/concepts-options/#web_password).",
)
def open_browser(url: str) -> bool:
"""
Open a URL in a browser window.
In contrast to webbrowser.open, we limit the list of suitable browsers.
This gracefully degrades to a no-op on headless servers, where webbrowser.open
would otherwise open lynx.
Returns:
True, if a browser has been opened
False, if no suitable browser has been found.
"""
browsers = (
"windows-default",
"macosx",
"wslview %s",
"gio",
"x-www-browser",
"gnome-open %s",
"xdg-open",
"google-chrome",
"chrome",
"chromium",
"chromium-browser",
"firefox",
"opera",
"safari",
)
for browser in browsers:
try:
b = webbrowser.get(browser)
except webbrowser.Error:
pass
else:
if b.open(url):
return True
return False