2222import sys
2323import tempfile
2424import time
25+ import datetime
2526
2627from collections import OrderedDict
2728
4647INITIAL_PID = os .getpid ()
4748
4849
50+ class AutoJSONEncoder (json .JSONEncoder ):
51+ """
52+ JSON encoder trying to_json() first
53+ """
54+ def default (self , obj ):
55+ try :
56+ return obj .to_json ()
57+ except AttributeError :
58+ return self .default_classic (obj )
59+
60+ def default_classic (self , o ):
61+ if isinstance (o , set ):
62+ return list (o )
63+ elif isinstance (o , datetime .datetime ):
64+ return (o - datetime .datetime (1970 , 1 , 1 )).total_seconds ()
65+ elif isinstance (o , bytes ):
66+ return o .decode ('UTF-8' )
67+ else :
68+ return super (AutoJSONEncoder , self ).default (o )
69+
70+
4971@zope .interface .implementer (interfaces .IAuthenticator )
5072@zope .interface .implementer (interfaces .IInstaller )
5173@zope .interface .provider (interfaces .IPluginFactory )
@@ -390,7 +412,7 @@ def _get_json_to_kwargs(self, json_data):
390412 n_data [k ] = val
391413 n_data ['cbot_' + k ] = val
392414
393- n_data ['cbot_json' ] = json . dumps (json_data )
415+ n_data ['cbot_json' ] = self . _json_dumps (json_data )
394416 return n_data
395417
396418 def _perform_http01_challenge (self , achall ):
@@ -542,6 +564,8 @@ def _perform_tlssni01_challenge(self, achall):
542564 except :
543565 pass
544566
567+ json_data = self ._json_sanitize_dict (json_data )
568+
545569 if self ._is_text_mode ():
546570 self ._notify_and_wait (
547571 self ._get_message (achall ).format (
@@ -750,17 +774,17 @@ def _json_sanitize_dict(self, dictionary):
750774 for key , val in list (dictionary .items ()):
751775 # Not highly efficient, would be neater to clean up FIELD_TOKEN.
752776 # But if any of the others turn to bytes in the future, this will solve it:
753- if type (key ) == bytes :
777+ if isinstance (key , bytes ) :
754778 del dictionary [key ]
755779 key = key .decode ('UTF-8' )
756780 dictionary [key ] = val
757781
758- if type (val ) == bytes :
782+ if isinstance (val , bytes ) :
759783 dictionary [key ] = val .decode ('UTF-8' )
760784 elif type (val ) in (list , tuple ):
761785 nval = []
762786 for item in val :
763- if type (item ) == bytes :
787+ if isinstance (item , bytes ) :
764788 item = item .decode ('UTF-8' )
765789 nval .append (item )
766790 dictionary [key ] = nval
@@ -848,6 +872,17 @@ def _is_dehydrated_dns(self):
848872 """
849873 return self .conf ("dehydrated-dns" )
850874
875+ def _json_dumps (self , data , ** kwargs ):
876+ """
877+ Dumps data to the json string
878+ Using custom serializer by default
879+ :param data:
880+ :param kwargs:
881+ :return:
882+ """
883+ kwargs .setdefault ('cls' , AutoJSONEncoder )
884+ return json .dumps (data , ** kwargs )
885+
851886 def _json_out (self , data , new_line = False ):
852887 """
853888 Dumps data as JSON to the stdout
@@ -856,7 +891,7 @@ def _json_out(self, data, new_line=False):
856891 :return:
857892 """
858893 # pylint: disable=no-self-use
859- json_str = json . dumps (data )
894+ json_str = self . _json_dumps (data )
860895 if new_line :
861896 json_str += '\n '
862897 sys .stdout .write (json_str )
0 commit comments