22
33import functools
44import hashlib
5- import hmac
65import json
76import logging
87import os .path
3736from mitmproxy .net .http import status_codes
3837from mitmproxy .tcp import TCPFlow
3938from mitmproxy .tcp import TCPMessage
39+ from mitmproxy .tools .web .webaddons import WebAuth
4040from mitmproxy .udp import UDPFlow
4141from mitmproxy .udp import UDPMessage
4242from mitmproxy .utils import asyncio_utils
@@ -221,6 +221,12 @@ def __init_subclass__(cls, **kwargs):
221221 if fn is not tornado .web .RequestHandler ._unimplemented_method :
222222 setattr (cls , method , AuthRequestHandler ._require_auth (fn ))
223223
224+ def auth_fail (self , invalid_password : bool ) -> None :
225+ """
226+ Will be called when returning a 403.
227+ May write a login form as the response.
228+ """
229+
224230 @staticmethod
225231 def _require_auth [** P , R ](
226232 fn : Callable [Concatenate [AuthRequestHandler , P ], R ],
@@ -230,13 +236,10 @@ def wrapper(
230236 self : AuthRequestHandler , * args : P .args , ** kwargs : P .kwargs
231237 ) -> R | None :
232238 if not self .current_user :
233- self .require_setting ("auth_token" , "AuthRequestHandler" )
234- if not hmac .compare_digest (
235- self .get_query_argument ("token" , default = "invalid" ),
236- self .settings ["auth_token" ],
237- ):
239+ password = self .get_argument ("token" , default = "" )
240+ if not self .settings ["is_valid_password" ](password ):
238241 self .set_status (403 )
239- self .render ( "login.html" )
242+ self .auth_fail ( bool ( password ) )
240243 return None
241244 self .set_signed_cookie (
242245 self .AUTH_COOKIE_NAME ,
@@ -332,6 +335,12 @@ def _is_fetch_mode_navigate(self) -> bool:
332335 # Forbid access for non-navigate fetch modes so that they can't obtain xsrf_token.
333336 return self .request .headers .get ("Sec-Fetch-Mode" , "navigate" ) == "navigate"
334337
338+ def auth_fail (self , invalid_password : bool ) -> None :
339+ # For mitmweb, we only write a login form for IndexHandler,
340+ # which has additional Sec-Fetch-Mode protections.
341+ if self ._is_fetch_mode_navigate ():
342+ self .render ("login.html" , invalid_password = invalid_password )
343+
335344 def get (self ):
336345 # Forbid access for non-navigate fetch modes so that they can't obtain xsrf_token.
337346 if self ._is_fetch_mode_navigate ():
@@ -342,6 +351,8 @@ def get(self):
342351 f"Unexpected Sec-Fetch-Mode header: { self .request .headers .get ('Sec-Fetch-Mode' )} " ,
343352 )
344353
354+ post = get # login form
355+
345356
346357class FilterHelp (RequestHandler ):
347358 def get (self ):
@@ -802,6 +813,7 @@ def __init__(
802813 self , master : mitmproxy .tools .web .master .WebMaster , debug : bool
803814 ) -> None :
804815 self .master = master
816+ auth_addon : WebAuth = master .addons .get ("webauth" )
805817 super ().__init__ (
806818 default_host = "dns-rebind-protection" ,
807819 template_path = os .path .join (os .path .dirname (__file__ ), "templates" ),
@@ -812,7 +824,7 @@ def __init__(
812824 debug = debug ,
813825 autoreload = False ,
814826 transforms = [GZipContentAndFlowFiles ],
815- auth_token = secrets . token_hex ( 16 ) ,
827+ is_valid_password = auth_addon . is_valid_password ,
816828 )
817829
818830 self .add_handlers ("dns-rebind-protection" , [(r"/.*" , DnsRebind )])
0 commit comments