a oey@s>dZddlZddlZddlmZddlmZddlZddl Z ddl Z ddl m Z ddl m Z ddl mZddl mZddl mZdd l mZdd l mZdd l mZddlZddlZddlZdd lmZdd lmZddlmZddlmZddlmZddlm Z ddlm!Z!e"e#Z$dZ%GdddZ&GdddZ'dS)zACME client API.N) parsedate_tz)Any)cast)List)Mapping)Optional)Set)Tuple)Union) HTTPAdapter)parse_header_links) challenges) crypto_util)errors)jws)messages-c@seZdZdZejdddddZejejddd Z ejejd d d Z dNeje ej ejd ddZ dOejeejdddZeejdddZejeejejfdddZdPeje ejejdddZejejejdddZejejdd d!ZdQejejeejd"d#d$ZdRejejeejd"d%d&Zeje dd'd(d)Z!ed*d+d,Z"e#e#ejd-d.d/Z$eje%e&e%d0d1d2Z'e(e%dejd3d4d5Z)e(dSeje e%e e%ejd6d7d8Z*ejej ejd9d:d;Z+e#e#ejd-dd?Z-ejejdd@dAZ.dTeje ej/e e%ejdBdCdDZ0ej1e2j3ej4dEdFdGZ5e(eje ejdHdIdJZ6eje e%ddKdLdMZ7dS)UClientV2zuACME client for a v2 API. :ivar messages.Directory directory: :ivar .ClientNetwork net: Client network. ClientNetworkN) directorynetreturncCs||_||_dS)zInitialize. :param .messages.Directory directory: Directory Resource :param .ClientNetwork net: Client network. N)rr)selfrrr,C:\Program Files\Certbot\pkgs\acme\client.py__init__*szClientV2.__init__) new_accountrcCsL||jd|}|jdkr6d|jvr6t|jd||}||j_|S)zRegister. :param .NewRegistration new_account: :raises .ConflictError: in case the account already exists :returns: Registration Resource. :rtype: `.RegistrationResource` newAccountLocation) _postr status_codeheadersr ConflictError_regr_from_responseraccount)rrresponseregrrrrr3s  zClientV2.new_account)r'rcCs||d|j_|jjS)zQuery server about registration. :param messages.RegistrationResource regr: Existing Registration Resource. T)_get_v2_accountrr%rr'rrrquery_registrationFszClientV2.query_registration)r'updatercCsJ||}|dur|jn|}tjfit|}|j||d}||j_|S)aKUpdate registration. :param messages.RegistrationResource regr: Registration Resource. :param messages.Registration update: Updated body of the resource. If not provided, body will be taken from `regr`. :returns: Updated Registration Resource. :rtype: `.RegistrationResource` Nbody)r(r-rZUpdateRegistrationdict_send_recv_regrrr%)rr'r+r-Z updated_regrrrrupdate_registrationRs  zClientV2.update_registrationF)r' update_bodyrcCsbd|j_|jjdd}||jd|}|jd}|j|rJtj | n|j|d}||j_|S)NT)Zonly_return_existingrrr-uri) rr%r-r+r rr"r Registration from_jsonjson)rr'r1Zonly_existing_regr&Z updated_uriZnew_regrrrrr(hs zClientV2._get_v2_account)csr_pemrc Cstjtjj|}t|}t|}g}|D]}|tj tj |dq.|D]}|tj tj |dqNtj |d}| |jd|} tj| } g} | jD]} | |j|| | dqtj| | jd| |dS)zRequest a new Order object from the server. :param bytes csr_pem: A CSR in PEM format. :returns: The newly created order. :rtype: OrderResource )typvalue) identifiersZnewOrderr3r)r-r3authorizationsr7)OpenSSLcryptoload_certificate_request FILETYPE_PEMrZ _pyopenssl_cert_or_req_all_namesZ_pyopenssl_cert_or_req_san_ipappendr IdentifierZIDENTIFIER_FQDNZ IDENTIFIER_IPZNewOrderr rOrderr5r6r<_authzr_from_response _post_as_get OrderResourcer"get) rr7csrZdnsNamesZipNamesr:nameZipsorderr&r-r<urlrrr new_orderts0         zClientV2.new_order)authzrrcCs(||j}|||jj|j}||fS)aPoll Authorization Resource for status. :param authzr: Authorization Resource :type authzr: `.AuthorizationResource` :returns: Updated Authorization Resource and HTTP response. :rtype: (`.AuthorizationResource`, `requests.Response`) )rEr3rDr- identifier)rrMr&Zupdated_authzrrrrpolls  z ClientV2.poll)orderrdeadlinercCs6|durtjtjdd}|||}|||S)adPoll authorizations and finalize the order. If no deadline is provided, this method will timeout after 90 seconds. :param messages.OrderResource orderr: order to finalize :param datetime.datetime deadline: when to stop polling and timeout :returns: finalized order :rtype: messages.OrderResource NZseconds)datetimenow timedeltapoll_authorizationsfinalize_order)rrPrQrrrpoll_and_finalizes zClientV2.poll_and_finalizecCsg}|jjD]L}tj|kr |j|||d}|jjtjkrL| |q t dqq t |t |jjkrvt g}|D]4}|jjtjkr~|jjD]}|jdur| |qq~|rt ||j|dS)zPoll Order Resource for status.r;N)r<)r-r<rUrVrDrEstatusrZSTATUS_PENDINGrAtimesleeplenr TimeoutError STATUS_VALIDr errorZValidationErrorr+)rrPrQZ responsesrKrMZfailedZchallrrrrXs&     zClientV2.poll_authorizations)rPrcCsRtjtjj|j}tjt|d}| |j j |}|j tj |d}|S)aStart the process of finalizing an order. :param messages.OrderResource orderr: order to finalize :param datetime.datetime deadline: when to stop polling and timeout :returns: updated order :rtype: messages.OrderResource )rHr,)r=r>r?r@r7rZCertificateRequestjoseComparableX509r r-finalizer+rCr5r6)rrPrHZ wrapped_csrresrrrbegin_finalizations  zClientV2.begin_finalization)rPrQfetch_alternative_chainsrc stj|krtd|j}tj| }|j tj krb|j durVt |j t dq|j tjkr|jdur|j}|j||jd}|rˆ|d}fdd|D}|j|d}|Sqt dS) z Poll an order that has been finalized for its status. If it becomes valid, obtain the certificate. :returns: finalized order (with certificate) :rtype: messages.OrderResource r[NzPThe certificate order failed. No further information was provided by the server.)r-Z fullchain_pemZ alternatecsg|]}|jqSr)rEtext).0rKrrr z.ClientV2.poll_finalization..)Zalternative_fullchains_pem)rUrVr]r^rEr3rrCr5r6r\ZSTATUS_INVALIDrbrZ IssuanceErrorErrorra certificater+ri _get_linksr`) rrPrQrhr&r-Zcertificate_responseZalt_chains_urlsZ alt_chainsrrkrpoll_finalizations&         zClientV2.poll_finalizationcCs||||||S)a{Finalize an order and obtain a certificate. :param messages.OrderResource orderr: order to finalize :param datetime.datetime deadline: when to stop polling and timeout :param bool fetch_alternative_chains: whether to also fetch alternative certificate chains :returns: finalized order :rtype: messages.OrderResource )rgrq)rrPrQrhrrrrYs zClientV2.finalize_order)certrsnrcCs||||jddS)aRevoke certificate. :param .ComparableX509 cert: `OpenSSL.crypto.X509` wrapped in `.ComparableX509` :param int rsn: Reason code for certificate revocation. :raises .ClientError: If revocation is unsuccessful. Z revokeCertN)_revoker)rrrrsrrrrevokes zClientV2.revokercCs$t|jdo"t|jjdo"|jjjS)zGChecks if ACME server requires External Account Binding authentication.metaexternal_account_required)hasattrrrwrxrkrrrrx"s   z"ClientV2.external_account_requiredargskwargsrcOs,|ddd|dd}|j|i|S)z Send GET request using the POST-as-GET protocol. :param args: :param kwargs: :return: Nr[N)r )rr{r|new_argsrrrrE(szClientV2._post_as_get)r& relation_typercs.d|jvrgSt|jd}fdd|DS)z Retrieves all Link URIs of relation_type from the response. :param requests.Response response: The requests HTTP response. :param str relation_type: The relation type to filter by. ZLinkcs0g|](}d|vrd|vr|dkr|dqS)relrKr)rjlrrrrl=sz'ClientV2._get_links..)r"r )rr&rlinksrrrrp2s zClientV2._get_links)rKrrcCstj||S)aB Retrieves the ACME directory (RFC 8555 section 7.1.1) from the ACME server. :param str url: the URL where the ACME directory is available :param ClientNetwork net: the ClientNetwork to use to make the request :returns: the ACME directory object :rtype: messages.Directory )r Directoryr5rGr6)clsrKrrrr get_directory@s zClientV2.get_directory)r&r3terms_of_servicercCs>d|jvr|jdd}tjtj||jd||dS)Nzterms-of-servicerKr)r-r3r)rrRegistrationResourcer4r5r6r"rG)rr&r3rrrrr$Ls  zClientV2._regr_from_response)r'r-rcCs"||j|}|j||j|jdS)N)r3r)r r3r$r)rr'r-r&rrrr/Xs zClientV2._send_recv_regrcOs&|dt|jd|jj|i|S)zWrapper around self.net.post that adds the newNonce URL. This is used to retry the request in case of a badNonce error. new_nonce_urlZnewNonce) setdefaultgetattrrrpostrr{r|rrrr fszClientV2._postcCs||tjdddS)zDeactivate registration. :param messages.RegistrationResource regr: The Registration Resource to be deactivated. :returns: The Registration resource that was deactivated. :rtype: `.RegistrationResource` deactivatedN)r\Zcontact)r0rr4r5r)rrrdeactivate_registrationos z ClientV2.deactivate_registrationcCs.tjdd}||j|}|||jj|jS)aDeactivate authorization. :param messages.AuthorizationResource authzr: The Authorization resource to be deactivated. :returns: The Authorization resource that was deactivated. :rtype: `.AuthorizationResource` r)r\)rZUpdateAuthorizationr r3rDr-rN)rrMr-r&rrrdeactivate_authorization}s  z!ClientV2.deactivate_authorization)r&rNr3rcCsFtjtj||jd|d}|durB|jj|krBt ||S)Nrr2) rAuthorizationResourceZ Authorizationr5r6r"rGr-rNrUnexpectedUpdate)rr&rNr3rMrrrrDs  zClientV2._authzr_from_response)challbr&rcCst||j|}z|jdd}Wnty<tdYn0tj|tj | d}|j|jkrpt |j|S)ahAnswer challenge. :param challb: Challenge Resource body. :type challb: `.ChallengeBody` :param response: Corresponding Challenge response :type response: `.challenges.ChallengeResponse` :returns: Challenge Resource with updated body. :rtype: `.ChallengeResource` :raises .UnexpectedUpdate: ZuprKz"up" Link header missing) authzr_urir-) r r3rKeyErrorr ClientErrorrChallengeResource ChallengeBodyr5r6r)rrr&ZresprZchallrrrranswer_challenges   zClientV2.answer_challenge)r&defaultrc Cs|jdt|}z t|}Wnxtyt|}|durz:t|ddurV|dnd}tj|dd|WYSttfyYn0|}Yn0tj tj|dS)aCompute next `poll` time based on response ``Retry-After`` header. Handles integers and various datestring formats per https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.37 :param requests.Response response: Response from `poll`. :param int default: Default value (in seconds), used when ``Retry-After`` header is not present or invalid. :returns: Time point when next `poll` should be performed. :rtype: `datetime.datetime` z Retry-AfterNrrS) r"rGstrint ValueErrorrrUrW OverflowErrorrV)rr&r retry_afterrTZwhenZtz_secsrrrrs   zClientV2.retry_after)rrrsrKrcCs0||tj||d}|jtjkr,tddS)a.Revoke certificate. :param .ComparableX509 cert: `OpenSSL.crypto.X509` wrapped in `.ComparableX509` :param int rsn: Reason code for certificate revocation. :param str url: ACME URL to post to :raises .ClientError: If revocation is unsuccessful. )roreasonz0Successful revocation must return HTTP OK statusN)r rZ Revocationr! http_clientZOKrr)rrrrsrKr&rrrrts  zClientV2._revoke)N)F)N)F)F)NN)NN)8__name__ __module__ __qualname____doc__rrrZNewRegistrationrrr*rr4r0boolr(bytesrFrLrr requestsResponserOrUrZrXrgrqrYrcrdrrurxrrErrrp classmethodrr$r/r rrrBrDrr ZChallengeResponserrrrtrrrrr#s    #     !             rc @s2eZdZdZdZdZdZdZdej dde fej e e jejeeedd d d Zdd d dZejeeedddZed)eje eejdddZeeeeejdddZeeejdddZefeeeejdddZejdddd Zeeed!d"d#Z eeejdd$d%Z!efeejeeejd&d'd(Z"dS)*rzvWrapper around requests that signs POSTs for authentication. Also adds user agent, and handles Content-Type. zapplication/jsonzapplication/jose+jsonzapplication/problem+jsonz Replay-NonceNTz acme-python)keyr%alg verify_ssl user_agenttimeoutrcCs\||_||_||_||_t|_||_t|_ ||_ t }|j d||j d|dS)Nzhttp://zhttps://) rr%rrset_noncesrrZSessionsession_default_timeoutr Zmount)rrr%rrrrZadapterrrrrs zClientNetwork.__init__rvcCs&z|jWnty Yn0dSr})rclose Exceptionrkrrr__del__s zClientNetwork.__del__)objnoncerKrcCs~|r|jddnd}td||j||d}|jdurJ|jd|d<|j|d <tjj |fit t t t f|jddS) zWrap `JSONDeSerializable` object in JWS. .. todo:: Implement ``acmePath``. :param josepy.JSONDeSerializable obj: :param str url: The URL to which this object will be POSTed :param str nonce: :rtype: str )indentrmzJWS payload: %s)rrrKNr3Zkidr)Z json_dumpsencodeloggerdebugrr%rrZJWSsignrrrr)rrrrKjobjr|rrr _wrap_in_jwss    zClientNetwork._wrap_in_jws)r& content_typerc Cs$|jd}|r"|dd}z |}WntyDd}Yn0|jdkrdt|jdd|j s|dur||j krt d|zt j|Wqtjy}zt||fWYd}~qd}~00n t|nD|dur||jkrt d |||jkr |dur td ||S) aCheck response content and its type. .. note:: Checking is not strict: wrong server response ``Content-Type`` HTTP header is ignored if response is an expected JSON object (c.f. Boulder #56). :param str content_type: Expected Content-Type response header. If JSON is expected and not present in server response, this function will raise an error. Otherwise, wrong Content-Type is ignored, but logged. :raises .messages.Error: If server response body carries HTTP Problem (https://datatracker.ietf.org/doc/html/rfc7807). :raises .ClientError: In case of other networking errors. Content-Type;rNirzUNKNOWN-LOCATIONz/Ignoring wrong Content-Type (%r) for JSON Errorzsz.ClientNetwork._send_request..)rrrrrrrZrequestr exceptionsZRequestExceptionrematchrgroupsrbase64Z b64encodeZcontentencodingrir!joinr"items)rrrKr{r|r&eZ err_regexmhostpathZ_err_noerr_msgZ debug_contentrrr _send_requestls<   . zClientNetwork._send_requestrzcOs|jdg|Ri|S)aSend HEAD request without checking the response. Note, that `_check_response` is not called, as it is expected that status code other than successfully 2xx will be returned, or messages2.Error will be raised by the server. ZHEAD)rrrrrheadszClientNetwork.head)rKrr|rcKs|j|jd|fi||dS)z$Send GET request and check response.ZGETr)rr)rrKrr|rrrrGszClientNetwork.get)r&rc Cs|j|jvr||j|j}ztjjd|}Wn2tjy`}zt ||WYd}~n d}~00t d||j |n t|dS)NrzStoring nonce: %s)REPLAY_NONCE_HEADERr"rZHeader_fieldsdecodercrrZBadNoncerrraddZ MissingNonce)rr&rZ decoded_noncerbrrr _add_nonces  " zClientNetwork._add_nonce)rKrrcCsL|jsBtd|dur$||}n|j||dd}|||jS)NzRequesting fresh noncer)rrrrrrpop)rrKrr&rrr _get_nonces   zClientNetwork._get_noncec Osrz|j|i|WStjyl}z@|jdkrVtd||j|i|WYd}~SWYd}~n d}~00dS)zPOST object wrapped in `.JWS` and check response. If the server responded with a badNonce error, the request will be retried once. ZbadNoncez Retrying request after error: %sN) _post_oncerrncoderr)rr{r|rbrrrrs  zClientNetwork.post)rKrrr|rcKsf|dd}||||||}|dd|i|jd|fd|i|}|j||d}|||S)Nrr"rrrr)rrrrrrr)rrKrrr|rrr&rrrrs  zClientNetwork._post_once)N)#rrrrrZJOSE_CONTENT_TYPErrrcZRS256DEFAULT_NETWORK_TIMEOUTZJWKrrrZ JWASignaturerrrrrZJSONDeSerializablerrrrrrrrrGrrrrrrrrrs>   :G    r)(rrrUZ email.utilsrZ http.clientZclientrZloggingrr]typingrrrrrrr r Zjosepyrcr=rZrequests.adaptersr Zrequests.utilsr Zacmer rrrrZ getLoggerrrrrrrrrrs@                  K