77logger = logging .getLogger (__name__ )
88
99class DiscordMiddleware :
10+ """
11+ Middleware for handling Discord interaction webhooks.
12+
13+ This middleware verifies the authenticity of Discord requests using Ed25519 signatures,
14+ and provides appropriate responses for different Discord interaction types.
15+ """
16+
1017 def __init__ (self , signature_verification_key = None ):
18+ """
19+ Initialize the Discord middleware with a signature verification key.
20+
21+ Args:
22+ signature_verification_key (str): The hexadecimal public key for verifying
23+ Discord's request signatures.
24+
25+ Raises:
26+ ValueError: If signature_verification_key is None.
27+ """
1128 if signature_verification_key is None :
1229 logger .error ("Signature verification key is required" )
1330 raise ValueError ("signature_verification_key is required" )
@@ -16,6 +33,19 @@ def __init__(self, signature_verification_key=None):
1633 logger .info ("DiscordMiddleware initialized with verification key" )
1734
1835 def invoke (self , r : Request ) -> Response :
36+ """
37+ Process an incoming request from Discord.
38+
39+ This method verifies the request signature, then determines the type of
40+ Discord interaction and returns the appropriate response.
41+
42+ Args:
43+ r (Request): The incoming request to process.
44+
45+ Returns:
46+ Response: A response to send back to Discord, or None if the request
47+ doesn't match any expected interaction type.
48+ """
1949 logger .debug ("Request received with body: %s" , r .data )
2050
2151 if not self .verify_request (r ):
@@ -24,34 +54,62 @@ def invoke(self, r: Request) -> Response:
2454
2555 logger .info ("Request signature verified" )
2656
27- if r .method == 'POST' and self .is_webhook_event (r ):
28- logger .info ("Ping received, sending ping response" )
29- return Response (json .dumps ({"type" : 1 }), content_type = "application/json" )
30-
31- elif r .method == 'POST' and self .is_ping (r ):
57+ if r .method == 'POST' and self .is_ping (r ):
3258 logger .info ("Ping received, sending ping response" )
3359 return Response (status = 204 )
60+ elif r .method == 'POST' and self .is_webhook_event (r ):
61+ logger .info ("Webhook event received, sending acknowledgment" )
62+ return Response (json .dumps ({"type" : 1 }), content_type = "application/json" )
3463
35- logger .info ("No ping response required " )
64+ logger .info ("No specific handler for this request " )
3665 return None
3766
3867 def is_webhook_event (self , request : Request ) -> bool :
68+ """
69+ Check if the request is a Discord webhook event (type 1).
70+
71+ Args:
72+ request (Request): The request to check.
73+
74+ Returns:
75+ bool: True if the request is a webhook event, False otherwise.
76+ """
3977 try :
4078 logger .debug ("Checking if request is a webhook event" )
4179 return request .json .get ('type' ) == 1
4280 except (TypeError , ValueError ) as e :
43- logger .error ("Failed to parse request JSON for request check: %s" , e )
81+ logger .error ("Failed to parse request JSON for webhook event check: %s" , e )
4482 return False
4583
4684 def is_ping (self , request : Request ) -> bool :
85+ """
86+ Check if the request is a Discord ping (type 0).
87+
88+ Discord sends this when registering a new webhook to verify it's working.
89+
90+ Args:
91+ request (Request): The request to check.
92+
93+ Returns:
94+ bool: True if the request is a ping, False otherwise.
95+ """
4796 try :
4897 logger .debug ("Checking if request is a ping" )
4998 return request .json .get ('type' ) == 0
5099 except (TypeError , ValueError ) as e :
51- logger .error ("Failed to parse request JSON for request check: %s" , e )
100+ logger .error ("Failed to parse request JSON for ping check: %s" , e )
52101 return False
53102
54103 def verify_request (self , request : Request ) -> bool :
104+ """
105+ Verify the authenticity of a Discord request using Ed25519 signatures.
106+
107+ Args:
108+ request (Request): The request to verify.
109+
110+ Returns:
111+ bool: True if the request signature is valid, False otherwise.
112+ """
55113 try :
56114 logger .debug ("Verifying request with headers: %s" , request .headers )
57115 signature = request .headers ['X-Signature-Ed25519' ]
0 commit comments