a ‚oetHã @s¾dZddlZddlZddlZddlmZmZmZmZm Z m Z m Z m Z m Z ddlmZddlmZmZmZmZe e¡Zd/eeee eegefe eegefedœdd „ZGd d „d ƒZGd d „d eƒZGdd„dejƒZe ddd�ZGdd„dej ej!ed�Z"e#edœdd„Z$d0ee e%ee#dœdd„Z&e#edœdd„Z'd1ee e%ee#dœdd „Z(ej)ed!œd"d#„Z*eej)d$œd%d&„Z+ej)ed'œd(d)„Z,eej)d$œd*d+„Z-e d,d-d�Z.Gd.d-„d-e"ƒZ/dS)2zÜJSON (de)serialization framework. The framework presented here is somewhat based on `Go's "json" package`_ (especially the ``omitempty`` functionality). .. _`Go's "json" package`: http://golang.org/pkg/encoding/json/ éN) ÚAnyÚCallableÚDictÚIterableÚListÚMappingÚOptionalÚTypeÚTypeVar)Úcrypto)Úb64ÚerrorsÚ interfacesÚutilF©Ú json_nameÚdefaultÚ omitemptyÚdecoderÚencoderÚreturncCst|||||d�S)a4Convenient function to declare a :class:`Field` with proper type annotations. This function allows to write the following code: import josepy class JSON(josepy.JSONObjectWithFields): typ: str = josepy.field('type') def other_type(self) -> str: return self.typ ©rrrrr)Ú _TypedFieldr©rú1C:\Program Files\Certbot\pkgs\josepy\json_util.pyÚfields ÿrc @súeZdZdZdZdeeeee egefee egefddœdd„Z e eedœd d „ƒZ eedœd d „Z edd œdd„Ze egefddœdd„Ze egefddœdd„Zeedœdd„Zeedœdd„Ze eedœdd„ƒZe eedœdd„ƒZdS)ÚFieldaøJSON object field. :class:`Field` is meant to be used together with :class:`JSONObjectWithFields`. ``encoder`` (``decoder``) is a callable that accepts a single parameter, i.e. a value to be encoded (decoded), and returns the serialized (deserialized) value. In case of errors it should raise :class:`~josepy.errors.SerializationError` (:class:`~josepy.errors.DeserializationError`). Note, that ``decoder`` should perform partial serialization only. :ivar str json_name: Name of the field when encoded to JSON. :ivar default: Default value (used when not present in JSON object). :ivar bool omitempty: If ``True`` and the field value is empty, then it will not be included in the serialized JSON object, and ``default`` will be used for deserialization. Otherwise, if ``False``, field is considered as required, value will always be included in the serialized JSON objected, and it must also be present when deserializing. )rrrÚfdecÚfencNFrcCs>||_||_||_|dur |jn||_|dur4|jn||_dS©N)rrrÚdefault_decoderrÚdefault_encoderr)ÚselfrrrrrrrrÚ__init__Rs zField.__init__©ÚvaluercCst|tƒ o| S)zÒIs the provided value considered "empty" for this field? This is useful for subclasses that might want to override the definition of being empty, e.g. for some more exotic data types. )Ú isinstanceÚbool©Úclsr%rrrÚ_emptyasz Field._emptycCs| |¡o|jS)zOmit the value in output?)r*r©r"r%rrrÚomitksz Field.omit©ÚkwargsrcKs0|j|j|j|j|jdœ|¥}t|ƒfi|¤ŽS)Nr)rrrrrÚtype)r"r.ÚcurrentrrrÚ_update_paramsosûúzField._update_params)rrcCs |j|d�S)z6Descriptor to change the decoder on JSON object field.)r©r1)r"rrrrrzsz Field.decoder)rrcCs |j|d�S)z6Descriptor to change the encoder on JSON object field.)rr2)r"rrrrr~sz Field.encodercCs | |¡S)z4Decode a value, optionally with context JSON object.)rr+rrrÚdecode‚sz Field.decodecCs | |¡S)z4Encode a value, optionally with context JSON object.)rr+rrrÚencode†sz Field.encodecsNt|tƒr t‡fdd„|DƒƒSt|tƒrFt ‡fdd„| ¡Dƒ¡S|SdS)zÃDefault decoder. Recursively deserialize into immutable types ( :class:`josepy.util.frozendict` instead of :func:`dict`, :func:`tuple` instead of :func:`list`). c3s|]}ˆ |¡VqdSr©r )Ú.0Zsubvalue©r)rrÚ •óz(Field.default_decoder..cs"i|]\}}ˆ |¡ˆ |¡“qSrr5)r6Úkeyr%r7rrÚ ˜sÿz)Field.default_decoder..N)r&ÚlistÚtupleÚdictrZ frozendictÚitemsr(rr7rr Šs   þÿzField.default_decodercCs|S)zDefault (passthrough) encoder.rr(rrrr! szField.default_encoder)NFNN)Ú__name__Ú __module__Ú __qualname__Ú__doc__Ú __slots__Ústrrr'rrr#Ú classmethodr*r,r1rrr3r4r r!rrrrr7s4úù   rc@seZdZdZdS)raSpecialized class to mark a JSON object field with typed annotations. This class is kept private because fields are supposed to be declared using the :function:`field` in this situation. In the future the :class:`Field` may be removed in favor of this one.N)r@rArBrCrrrrr¨src@sReZdZUdZiZeeefed<e eed<ee eeee fddœdd„Z dS)ÚJSONObjectWithFieldsMetaa»Metaclass for :class:`JSONObjectWithFields` and its subclasses. It makes sure that, for any class ``cls`` with ``__metaclass__`` set to ``JSONObjectWithFieldsMeta``: 1. All fields (attributes of type :class:`Field`) in the class definition are moved to the ``cls._fields`` dictionary, where keys are field attribute names and values are fields themselves. 2. ``cls.__slots__`` is extended by all field attribute names (i.e. not :attr:`Field.json_name`). Original ``cls.__slots__`` are stored in ``cls._orig_slots``. In a consequence, for a field attribute name ``some_field``, ``cls.some_field`` will be a slot descriptor and not an instance of :class:`Field`. For example:: some_field = Field('someField', default=()) class Foo: __metaclass__ = JSONObjectWithFieldsMeta __slots__ = ('baz',) some_field = some_field assert Foo.__slots__ == ('some_field', 'baz') assert Foo._orig_slots == () assert Foo.some_field is not Field assert Foo._fields.keys() == ['some_field'] assert Foo._fields['some_field'] is some_field As an implementation note, this metaclass inherits from :class:`abc.ABCMeta` (and not the usual :class:`type`) to mitigate the metaclass conflict (:class:`ImmutableMap` and :class:`JSONDeSerializable`, parents of :class:`JSONObjectWithFields`, use :class:`abc.ABCMeta` as its metaclass). Ú_fieldsÚ _orig_slots)ÚnameÚbasesÚ namespacercCsÈi}|D]}| t|diƒ¡q| ¡ ¡D]P\}}t|tƒr,t|tƒrn|| di¡vrntd|›d|›d�ƒ‚|  |¡||<q,| dd¡|d<t t |dƒt |  ¡ƒƒ|d<||d<t j ||||¡S) NrHÚ__annotations__zField `z` in JSONObject `z` has no type annotation.rDrrI)ÚupdateÚgetattrÚcopyr?r&rrÚgetÚ ValueErrorÚpopr=r<ÚkeysÚabcÚABCMetaÚ__new__)ZmcsrJrKrLÚfieldsÚbaser:r%rrrrWÜs  ÿ z JSONObjectWithFieldsMeta.__new__N) r@rArBrCrHrrErrMrrrrWrrrrrG±s ' þrGÚGenericJSONObjectWithFieldsÚJSONObjectWithFields)ÚboundcsØeZdZdZeeeefdœdd„ƒZeddœ‡fdd„ Z eed œd d „Z eeefdœd d „Z eeefdœdd„Z ee eefddœdd„ƒZee eefedœdd„ƒZeeee eefedœdd„ƒZ‡ZS)r[aÒJSON object with fields. Example:: class Foo(JSONObjectWithFields): bar = Field('Bar') empty = Field('Empty', omitempty=True) @bar.encoder def bar(value): return value + 'bar' @bar.decoder def bar(value): if not value.endswith('bar'): raise errors.DeserializationError('No bar suffix!') return value[:-3] assert Foo(bar='baz').to_partial_json() == {'Bar': 'bazbar'} assert Foo.from_json({'Bar': 'bazbar'}) == Foo(bar='baz') assert (Foo.from_json({'Bar': 'bazbar', 'Empty': '!'}) == Foo(bar='baz', empty='!')) assert Foo(bar='baz').bar == 'baz' ©rcCsdd„|j ¡DƒS)zGet default fields values.cSsi|]\}}||j“qSr)r)r6Úslotrrrrr;r9z2JSONObjectWithFields._defaults..)rHr?r7rrrÚ _defaultsszJSONObjectWithFields._defaultsNr-c s"tƒjfii| ¡¥|¥¤ŽdSr)Úsuperr#r_)r"r.©Ú __class__rrr#szJSONObjectWithFields.__init__)rJrcCsBz|j|}Wn"ty0t d |¡¡‚Yn0| t||ƒ¡S)zßEncode a single field. :param str name: Name of the field to be encoded. :raises errors.SerializationError: if field cannot be serialized :raises errors.Error: if field could not be found zField not found: {0})rHÚKeyErrorr ÚErrorÚformatr4rO)r"rJrrrrr4s  zJSONObjectWithFields.encodec Cs–i}tƒ}|j ¡D]|\}}t||ƒ}| |¡r@| ||f¡qz| |¡||j<Wqtj yŽ}z t  d  |||¡¡‚WYd}~qd}~00q|S)zSerialize fields to JSON.zCould not encode {0} ({1}): {2}N) ÚsetrHr?rOr,Úaddr4rr ZSerializationErrorre)r"ÚjobjZomittedr^rr%ÚerrorrrrÚfields_to_partial_json/s   ÿz+JSONObjectWithFields.fields_to_partial_jsoncCs| ¡Sr)rj)r"rrrÚto_partial_jsonAsz$JSONObjectWithFields.to_partial_json©rhrcCsTtƒ}|j ¡D]$\}}|js|j|vr| |j¡q|rPt d d  |¡¡¡‚dS)Nz&The following fields are required: {0}ú,) rfrHr?rrrgr ÚDeserializationErrorreÚjoin)r)rhÚmissingÚ_rrrrÚ_check_requiredDsÿz$JSONObjectWithFields._check_requiredc Csš| |¡i}|j ¡D]|\}}|j|vr<|jr<|j||<q||j}z| |¡||<Wqtjy’}z t d  |||¡¡‚WYd}~qd}~00q|S)zDeserialize fields from JSON.z#Could not decode {0!r} ({1!r}): {2}N) rrrHr?rrrr3r rnre)r)rhrXr^rr%rirrrÚfields_from_jsonPs    ÿz%JSONObjectWithFields.fields_from_json)r)rhrcCs|fi| |¡¤ŽSr)rs)r)rhrrrÚ from_jsonbszJSONObjectWithFields.from_json)r@rArBrCrFrrErr_r#r4rjrkrrrrsr rZrtÚ __classcell__rrrarr[ús þ)Ú metaclass)ÚdatarcCst |¡ d¡S)zJEncode JOSE Base-64 field. :param bytes data: :rtype: `str` Úascii)r Z b64encoder3)rwrrrÚencode_b64joseisry)rwÚsizeÚminimumrc Cs€zt | ¡¡}Wn0tjyB}zt |¡‚WYd}~n d}~00|dur||s\t|ƒ|ksl|r|t|ƒ|kr|t d |¡¡‚|S)aDecode JOSE Base-64 field. :param unicode data: :param int size: Required length (after decoding). :param bool minimum: If ``True``, then `size` will be treated as minimum required length, as opposed to exact equality. :rtype: bytes Nz&Expected at least or exactly {0} bytes) r Z b64decoder4Úbinasciirdr rnÚlenre)rwrzr{ZdecodedrirrrÚdecode_b64josets  ÿ ÿÿ ÿr~r$cCst |¡ ¡S)z;Hexlify. :param bytes value: :rtype: unicode )r|Zhexlifyr3)r%rrrÚ encode_hex16Œsr)r%rzr{rc Cs‚| ¡}|dur@|s$t|ƒ|dks8|r@t|ƒ|dkr@t ¡‚z t |¡WStjy|}zt |¡‚WYd}~n d}~00dS)aDecode hexlified field. :param unicode value: :param int size: Required length (after decoding). :param bool minimum: If ``True``, then `size` will be treated as minimum required length, as opposed to exact equality. :rtype: bytes Né)r4r}r rnr|Z unhexlifyrd)r%rzr{Zvalue_brirrrÚ decode_hex16–s ÿÿÿÿ r�)ÚcertrcCs*t|jtjƒrtdƒ‚tt tj|j¡ƒS)z…Encode certificate as JOSE Base-64 DER. :type cert: `OpenSSL.crypto.X509` wrapped in `.ComparableX509` :rtype: unicode z.Error input is actually a certificate request.)r&Úwrappedr ZX509ReqrRryZdump_certificateÚ FILETYPE_ASN1)r‚rrrÚ encode_cert¬sr…)Úb64derrc CsPzt t tjt|ƒ¡¡WStjyJ}zt |¡‚WYd}~n d}~00dS)z�Decode JOSE Base-64 DER-encoded certificate. :param unicode b64der: :rtype: `OpenSSL.crypto.X509` wrapped in `.ComparableX509` N) rÚComparableX509r Zload_certificater„r~rdr rn©r†rirrrÚ decode_cert¹s ÿr‰)ÚcsrrcCs*t|jtjƒrtdƒ‚tt tj|j¡ƒS)zEncode CSR as JOSE Base-64 DER. :type csr: `OpenSSL.crypto.X509Req` wrapped in `.ComparableX509` :rtype: unicode z&Error input is actually a certificate.)r&rƒr ZX509rRryZdump_certificate_requestr„)rŠrrrÚ encode_csrÈsr‹c CsPzt t tjt|ƒ¡¡WStjyJ}zt |¡‚WYd}~n d}~00dS)zˆDecode JOSE Base-64 DER-encoded CSR. :param unicode b64der: :rtype: `OpenSSL.crypto.X509Req` wrapped in `.ComparableX509` N) rr‡r Zload_certificate_requestr„r~rdr rnrˆrrrÚ decode_csrÕs ÿrŒÚ GenericTypedJSONObjectWithFieldsÚTypedJSONObjectWithFieldsc@s´eZdZUdZeZeed<dZeed<eZ e ee fed<e de e eee e dœdd „ƒZe eeefe dd œd d „ƒZe eefd œdd„Ze eeefdd œdd„ƒZdS)rŽzJSON object with type.Útypr/Útype_field_nameÚTYPESN)Útype_clsr�rcCs |dur|jn|}||j|<|S)z(Register class for JSON deserialization.N)r�r‘)r)r’r�rrrÚregisterùs z"TypedJSONObjectWithFields.registerrlcCs¤||j ¡vr.|j|vr*t d |j¡¡‚|St|tƒsHt d |¡¡‚z||j}Wntyrt d¡‚Yn0z |j|WStyžt  ||¡‚Yn0dS)z&Get the registered class for ``jobj``.zMissing type field ({0})z{0} is not a dictionary objectzmissing type fieldN) r‘Úvaluesr�r rnrer&r>rcZUnrecognizedTypeError)r)rhr�rrrÚ get_type_clss   ÿ    z&TypedJSONObjectWithFields.get_type_clsr]cCs| ¡}|j||j<|S)aGet JSON serializable object. :returns: Serializable JSON object representing ACME typed object. :meth:`validate` will almost certainly not work, due to reasons explained in :class:`josepy.interfaces.IJSONSerializable`. :rtype: dict )rjr�r�)r"rhrrrrks  z)TypedJSONObjectWithFields.to_partial_jsoncCs| |¡}|fi| |¡¤ŽS)z¯Deserialize ACME object from valid JSON object. :raises josepy.errors.UnrecognizedTypeError: if type of the ACME object has not been registered. )r•rs)r)rhr’rrrrt(s z#TypedJSONObjectWithFields.from_json)N)r@rArBrCÚNotImplementedr�rErMr�r‘rr rFr�rr“rrr•rkrtrrrrrŽés   ÿ þ )NFNN)NF)NF)0rCrUr|ZloggingÚtypingrrrrrrrr r ZOpenSSLr Zjosepyr r rrZ getLoggerr@ÚloggerrEr'rrrrVrGrZZ ImmutableMapZJSONDeSerializabler[ÚbytesryÚintr~rr�r‡r…r‰r‹rŒr�rŽrrrrÚsL,  ûú q F   ÿo    ÿ