1- # hmac_signature_verifier.py
21import hmac
32import hashlib
43from typing import Callable , Optional , Union
@@ -41,7 +40,7 @@ class HmacSignatureVerifier(SignatureVerifier):
4140
4241 Parameters
4342 ----------
44- key : str
43+ secret_key : str
4544 Shared secret used for HMAC.
4645 signature_header : str
4746 Header name containing the provided signature (case-insensitive lookup).
@@ -60,41 +59,41 @@ class HmacSignatureVerifier(SignatureVerifier):
6059 def __init__ (
6160 self ,
6261 * ,
63- key : str ,
62+ secret_key : str ,
6463 signature_header : str ,
6564 canonical_message_builder : Optional [Callable [[Request ], Union [bytes , str , None ]]] = None ,
6665 hash_alg = hashlib .sha256 ,
67- encoder : Optional [DigestEncoder ] = None ,
68- signature_value_template : Optional [str ] = None ,
66+ encoder : Optional [DigestEncoder ] = HexEncoder () ,
67+ signature_value_template : Optional [str ] = '{digest}' ,
6968 ) -> None :
70- if not isinstance (key , str ) or not key :
71- raise ValueError ("key must be a non-empty string. " )
69+ if not isinstance (secret_key , str ) or not secret_key :
70+ raise ValueError ("key must be a non-empty string" )
7271 if not isinstance (signature_header , str ) or not signature_header .strip ():
73- raise ValueError ("signature_header must be a non-empty string. " )
72+ raise ValueError ("signature_header must be a non-empty string" )
7473
75- self ._key_bytes = key . encode ( "utf-8" )
74+ self ._secret_key = secret_key
7675 self ._signature_header_lc = signature_header .lower ().strip ()
7776 self ._message_resolver = canonical_message_builder
7877 self ._hash_alg = hash_alg
79- self ._encoder = encoder or HexEncoder ()
78+ self ._encoder = encoder
8079 self ._signature_value_template = signature_value_template
8180
8281 def verify (self , request : Request ) -> SignatureVerificationResult :
8382 try :
8483 provided = self ._read_signature_header (request )
8584 if provided is None :
8685 return SignatureVerificationResult .failed (
87- ValueError (f"Signature header '{ self ._signature_header_lc } ' is missing. " )
86+ ValueError (f"Signature header '{ self ._signature_header_lc } ' is missing" )
8887 )
8988
9089 message_bytes = self ._resolve_message_bytes (request )
91- digest = hmac .new (self ._key_bytes , message_bytes , self ._hash_alg ).digest ()
90+ digest = hmac .new (self ._secret_key . encode ( "utf-8" ) , message_bytes , self ._hash_alg ).digest ()
9291 encoded_digest = self ._encoder .encode (digest )
93- expected = self ._wrap_expected_signature ( encoded_digest )
92+ expected = self ._signature_value_template . replace ( "{digest}" , encoded_digest )
9493
9594 is_match = hmac .compare_digest (provided , expected )
9695 return SignatureVerificationResult .passed () if is_match else SignatureVerificationResult .failed (
97- SignatureVerificationError ("Signature mismatch. " )
96+ SignatureVerificationError ("Signature mismatch" )
9897 )
9998 except Exception as exc :
10099 return SignatureVerificationResult .failed (
@@ -109,28 +108,7 @@ def _read_signature_header(self, request: Request) -> Optional[str]:
109108 return None if value is None or value .strip () == "" else value
110109
111110 def _resolve_message_bytes (self , request : Request ) -> bytes :
112- """
113- Resolve the message to be signed:
114- - If message_resolver is provided and returns bytes/str -> use it.
115- If it returns None -> fall back to raw/text body.
116- - If no resolver provided -> fall back to raw/text body.
117- """
118- if callable (self ._message_resolver ):
119- resolved = self ._message_resolver (request )
120- if isinstance (resolved , bytes ):
121- return resolved
122- if isinstance (resolved , str ):
123- return resolved .encode ("utf-8" )
124- # resolved is None -> fall through to default
125- # default fallback: prefer raw_body, else textual body
126- raw = getattr (request , "raw_body" , None )
127- if isinstance (raw , (bytes , bytearray )):
128- return bytes (raw )
129- body = getattr (request , "body" , None )
130- return (body or "" ).encode ("utf-8" )
131-
132- def _wrap_expected_signature (self , encoded_digest : str ) -> str :
133- template = self ._signature_value_template
134- if not template :
135- return encoded_digest
136- return template .replace ("{digest}" , encoded_digest ) if "{digest}" in template else template
111+ if self ._message_resolver is None :
112+ return request .raw_body
113+
114+ return self ._message_resolver (request )
0 commit comments