1010from Crypto .PublicKey import RSA , ECC
1111from Crypto .Hash import SHA256
1212from Crypto .Signature import pkcs1_15 , eddsa
13+ import urllib .parse as _urlencode
1314from operator import itemgetter
1415from urllib .parse import urlencode
1516
@@ -59,6 +60,8 @@ class BaseClient:
5960
6061 REQUEST_TIMEOUT : float = 10
6162
63+ REQUEST_RECVWINDOW : int = 10000 # 10 seconds
64+
6265 SYMBOL_TYPE_SPOT = "SPOT"
6366
6467 ORDER_STATUS_NEW = "NEW"
@@ -300,13 +303,21 @@ def _rsa_signature(self, query_string: str):
300303 assert self .PRIVATE_KEY
301304 h = SHA256 .new (query_string .encode ("utf-8" ))
302305 signature = pkcs1_15 .new (self .PRIVATE_KEY ).sign (h ) # type: ignore
303- return b64encode (signature ).decode ()
306+ res = b64encode (signature ).decode ()
307+ # return self.encode_uri_component(res)
308+ return res
309+
310+ @staticmethod
311+ def encode_uri_component (uri , safe = "~()*!.'" ):
312+ return _urlencode .quote (uri , safe = safe )
304313
305314 def _ed25519_signature (self , query_string : str ):
306315 assert self .PRIVATE_KEY
307- return b64encode (
316+ res = b64encode (
308317 eddsa .new (self .PRIVATE_KEY , "rfc8032" ).sign (query_string .encode ())
309318 ).decode () # type: ignore
319+ # return self.encode_uri_component(res)
320+ return res
310321
311322 def _hmac_signature (self , query_string : str ) -> str :
312323 assert self .API_SECRET , "API Secret required for private endpoints"
@@ -317,15 +328,16 @@ def _hmac_signature(self, query_string: str) -> str:
317328 )
318329 return m .hexdigest ()
319330
320- def _generate_signature (self , data : Dict ) -> str :
331+ def _generate_signature (self , data : Dict , uri_encode = True ) -> str :
321332 sig_func = self ._hmac_signature
322333 if self .PRIVATE_KEY :
323334 if self ._is_rsa :
324335 sig_func = self ._rsa_signature
325336 else :
326337 sig_func = self ._ed25519_signature
327338 query_string = "&" .join ([f"{ d [0 ]} ={ d [1 ]} " for d in self ._order_params (data )])
328- return sig_func (query_string )
339+ res = sig_func (query_string )
340+ return self .encode_uri_component (res ) if uri_encode else res
329341
330342 def _sign_ws_params (self , params , signature_func ):
331343 if "signature" in params :
@@ -445,6 +457,8 @@ def _get_request_kwargs(
445457 kwargs ["data" ]["timestamp" ] = int (
446458 time .time () * 1000 + self .timestamp_offset
447459 )
460+ if self .REQUEST_RECVWINDOW :
461+ kwargs ["data" ]["recvWindow" ] = self .REQUEST_RECVWINDOW
448462 kwargs ["data" ]["signature" ] = self ._generate_signature (kwargs ["data" ])
449463
450464 # sort get and post params to match signature order
0 commit comments