123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755letletsencrypt_production_url="https://acme-v02.api.letsencrypt.org/directory"letletsencrypt_staging_url="https://acme-staging-v02.api.letsencrypt.org/directory"letsha256_and_base64a=letopenDigestif.SHA256inleta=digest_stringainleta=to_raw_stringainJws.Base64u.encodealeterror_msgffmt=Fmt.kstr(funmsg->Error(`Msgmsg))fmtmoduleS=Map.Make(String)moduleDirectory=structtypemeta={termsOfService:stringoption;website:stringoption;caaIdentities:stringlist;externalAccountRequired:bool}letpp_metappf{termsOfService;website;caaIdentities;_}=Fmt.pfppf"terms of service: %a@,website %a@,caa identities %a"Fmt.(option~none:(any"no tos")string)termsOfServiceFmt.(option~none:(any"no website")string)websiteFmt.(list~sep:(any", ")string)caaIdentitiestypet={newAccount:string;newNonce:string;newOrder:string;revokeCert:string;keyChange:string;newAuthz:stringoption;meta:metaoption}letppppfdir=Fmt.pfppf"new nonce %s@,new account %s@,new order %s@,new authz %a@,revoke cert %s@,key change %s@,meta %a"dir.newNoncedir.newAccountdir.newOrderFmt.(option~none:(any"no authz")string)dir.newAuthzdir.revokeCertdir.keyChangeFmt.(option~none:(any"no meta")pp_meta)dir.metamoduleOptics=structlettermsOfService()=Lun.lense(fun{termsOfService;_}->termsOfService)(funttermsOfService->{twithtermsOfService})letwebsite()=Lun.lense(fun{website;_}->website)(funtwebsite->{twithwebsite})letcaaIdentities()=Lun.lense(fun{caaIdentities;_}->caaIdentities)(funtcaaIdentities->{twithcaaIdentities})letexternalAccountRequired()=Lun.lense(fun{externalAccountRequired;_}->externalAccountRequired)(funtexternalAccountRequired->{twithexternalAccountRequired})letnewAccount()=Lun.lense(fun{newAccount;_}->newAccount)(funtnewAccount->{twithnewAccount})letnewNonce()=Lun.lense(fun{newNonce;_}->newNonce)(funtnewNonce->{twithnewNonce})letnewOrder()=Lun.lense(fun{newOrder;_}->newOrder)(funtnewOrder->{twithnewOrder})letrevokeCert()=Lun.lense(fun{revokeCert;_}->revokeCert)(funtrevokeCert->{twithrevokeCert})letkeyChange()=Lun.lense(fun{keyChange;_}->keyChange)(funtkeyChange->{twithkeyChange})letnewAuthz()=Lun.lense(fun{newAuthz;_}->newAuthz)(funtnewAuthz->{twithnewAuthz})letmeta()=Lun.lense(fun{meta;_}->meta)(funtmeta->{twithmeta})endletmeta=letopenJsontinlettermsOfService=letenc=Lun.getOptics.termsOfServiceinObject.opt_mem"termsOfService"~encstringinletwebsite=letenc=Lun.getOptics.websiteinObject.opt_mem"website"~encstringinletcaaIdentities=letenc=Lun.getOptics.caaIdentitiesinletdec_absent=[]inletenc_omit=function[]->true|_->falseinObject.mem"caaIdentities"~enc~dec_absent~enc_omit(liststring)inletexternalAccountRequired=letenc=Lun.getOptics.externalAccountRequiredinletdec_absent=falseinletenc_omit=Fun.negateFun.idinObject.mem"externalAccountRequired"~enc~dec_absent~enc_omitboolinletfntermsOfServicewebsitecaaIdentitiesexternalAccountRequired={termsOfService;website;caaIdentities;externalAccountRequired}inObject.mapfn|>termsOfService|>website|>caaIdentities|>externalAccountRequired|>Object.finishlett=letopenJsontinletnewAccount=letenc=Lun.getOptics.newAccountinObject.mem"newAccount"~encstringinletnewNonce=letenc=Lun.getOptics.newNonceinObject.mem"newNonce"~encstringinletnewOrder=letenc=Lun.getOptics.newOrderinObject.mem"newOrder"~encstringinletrevokeCert=letenc=Lun.getOptics.revokeCertinObject.mem"revokeCert"~encstringinletkeyChange=letenc=Lun.getOptics.keyChangeinObject.mem"keyChange"~encstringinletnewAuthz=letenc=Lun.getOptics.newAuthzinObject.opt_mem"newAuthz"~encstringinletmeta=letenc=Lun.getOptics.metainObject.opt_mem"meta"~encmetainletfnnewAccountnewNoncenewOrderrevokeCertkeyChangenewAuthzmeta={newAccount;newNonce;newOrder;revokeCert;keyChange;newAuthz;meta}inObject.mapfn|>newAccount|>newNonce|>newOrder|>revokeCert|>keyChange|>newAuthz|>meta|>Object.finishletdecodestr=matchJsont_bytesrw.decode_stringtstrwith|Okt->Okt|Error_->error_msgf"Invalid directory object"endmoduleAccount=structtypestatus=|Valid|Deactivated|Revokedletstatus=letvalid="valid",Validanddeactived="deactived",Deactivatedandrevoked="revoked",RevokedinJsont.enum[valid;deactived;revoked]typet={status:status;contact:stringlist;termsOfServiceAgreed:bool;orders:string}letpp_statusppfs=Fmt.stringppf(matchswith|Valid->"valid"|Deactivated->"deactivated"|Revoked->"revoked")letppppfa=Fmt.pfppf"status %a@,contact %a@,terms of service agreed %b@,orders %s"pp_statusa.statusFmt.(list~sep:(any", ")string)a.contacta.termsOfServiceAgreeda.ordersmoduleOptics=structletstatus()=Lun.lense(fun{status;_}->status)(funtstatus->{twithstatus})letcontact()=Lun.lense(fun{contact;_}->contact)(funtcontact->{twithcontact})lettermsOfServiceAgreed()=Lun.lense(fun{termsOfServiceAgreed;_}->termsOfServiceAgreed)(funttermsOfServiceAgreed->{twithtermsOfServiceAgreed})letorders()=Lun.lense(fun{orders;_}->orders)(funtorders->{twithorders})endlett=letopenJsontinletstatus=letenc=Lun.getOptics.statusinObject.mem"status"~encstatusinletcontact=letenc=Lun.getOptics.contactinObject.mem"contact"~enc(liststring)inlettermsOfServiceAgreed=letenc=Lun.getOptics.termsOfServiceAgreedinletdec_absent=falseinletenc_omit=Fun.negateFun.idinObject.mem"termsOfServiceAgreed"~enc~dec_absent~enc_omitboolinletorders=letenc=Lun.getOptics.ordersinObject.mem"orders"~encstringinletfnstatuscontacttermsOfServiceAgreedorders={status;contact;termsOfServiceAgreed;orders}inObject.mapfn|>status|>contact|>termsOfServiceAgreed|>orders|>Object.finishletdecodestr=matchJsont_bytesrw.decode_stringtstrwith|Okt->Okt|Error_->error_msgf"Invalid account object"endletrfc3339=letdecstr=matchPtime.of_rfc3339strwith|Ok(t,_,_)->t|Error_->failwith"Invalid RFC3339 date"inletencstr=Ptime.to_rfc3339strinJsont.map~dec~encJsont.stringletpp_idppfstr=Fmt.pfppf"DNS - %s"strletpp_json=letopenFmtinDump.iter_bindingsS.iter(any"mems")stringJsont.pp_jsonmoduleOrder=structtypestatus=|Pending|Ready|Processing|Valid|Invalidletstatus=letpending="pending",Pendingandready="ready",Readyandprocessing="processing",Processingandvalid="valid",Validandinvalid="invalid",InvalidinJsont.enum[pending;ready;processing;valid;invalid]letidentifier=letopenJsontinlett=Object.mem"type"(conststring"dns")inletidentifier=Object.mem"value"stringinObject.map(fun_identifier->identifier)|>t|>identifier|>Object.finishtypet={status:status;expires:Ptime.toption;identifiers:stringlist;notBefore:Ptime.toption;notAfter:Ptime.toption;error:Jsont.jsonS.toption;authorizations:stringlist;finalize:string;certificate:stringoption}letpp_statusppfs=Fmt.stringppf(matchswith|Pending->"pending"|Ready->"ready"|Processing->"processing"|Valid->"valid"|Invalid->"invalid")letppppfo=Fmt.pfppf"status %a@,expires %a@,identifiers %a@,not_before %a@,not_after %a@,error %a@,authorizations %a@,finalize %s@,certificate %a"pp_statuso.statusFmt.(option~none:(any"no")(Ptime.pp_rfc3339()))o.expiresFmt.(list~sep:(any", ")pp_id)o.identifiersFmt.(option~none:(any"no")(Ptime.pp_rfc3339()))o.notBeforeFmt.(option~none:(any"no")(Ptime.pp_rfc3339()))o.notAfterFmt.(option~none:(any"no error")pp_json)o.errorFmt.(list~sep:(any", ")string)o.authorizationso.finalizeFmt.(option~none:(any"no")string)o.certificatemoduleOptics=structletstatus()=Lun.lense(fun{status;_}->status)(funtstatus->{twithstatus})letexpires()=Lun.lense(fun{expires;_}->expires)(funtexpires->{twithexpires})letidentifiers()=Lun.lense(fun{identifiers;_}->identifiers)(funtidentifiers->{twithidentifiers})letnotBefore()=Lun.lense(fun{notBefore;_}->notBefore)(funtnotBefore->{twithnotBefore})letnotAfter()=Lun.lense(fun{notAfter;_}->notAfter)(funtnotAfter->{twithnotAfter})leterror()=Lun.lense(fun{error;_}->error)(funterror->{twitherror})letauthorizations()=Lun.lense(fun{authorizations;_}->authorizations)(funtauthorizations->{twithauthorizations})letfinalize()=Lun.lense(fun{finalize;_}->finalize)(funtfinalize->{twithfinalize})letcertificate()=Lun.lense(fun{certificate;_}->certificate)(funtcertificate->{twithcertificate})endlett=letopenJsontinletstatus=letenc=Lun.getOptics.statusinObject.mem"status"~encstatusinletexpires=letenc=Lun.getOptics.expiresinObject.opt_mem"expires"~encrfc3339inletidentifiers=letenc=Lun.getOptics.identifiersinObject.mem"identifiers"~enc(listidentifier)inletnotBefore=letenc=Lun.getOptics.notBeforeinObject.opt_mem"notBefore"~encrfc3339inletnotAfter=letenc=Lun.getOptics.notAfterinObject.opt_mem"notAfter"~encrfc3339inleterror=letenc=Lun.getOptics.errorinObject.opt_mem"error"~enc(Object.as_string_mapjson)inletauthorizations=letenc=Lun.getOptics.authorizationsinObject.mem"authorizations"~enc(liststring)inletfinalize=letenc=Lun.getOptics.finalizeinObject.mem"finalize"~encstringinletcertificate=letenc=Lun.getOptics.certificateinObject.opt_mem"certificate"~encstringinletfnstatusexpiresidentifiersnotBeforenotAftererrorauthorizationsfinalizecertificate={status;expires;identifiers;notBefore;notAfter;error;authorizations;finalize;certificate}inObject.mapfn|>status|>expires|>identifiers|>notBefore|>notAfter|>error|>authorizations|>finalize|>certificate|>Object.finishletdecodestr=matchJsont_bytesrw.decode_stringtstrwith|Okt->Okt|Error_->error_msgf"Invalid order object"endmoduleChallenge=structtypetyp=DNS|HTTP|ALPNletpp_typppft=Fmt.stringppf(matchtwithDNS->"DNS"|HTTP->"HTTP"|ALPN->"ALPN")lettyp=letdns="dns-01",DNSandhttp="http-01",HTTPandalpn="tls-alpn-01",ALPNinJsont.enum[dns;http;alpn]typestatus=|Pending|Processing|Valid|Invalidletstatus=letpending="pending",Pendingandprocessing="processing",Processingandvalid="valid",Validandinvalid="invalid",InvalidinJsont.enum[pending;processing;valid;invalid]typet={typ:typ;url:string;status:status;validated:Ptime.toption;error:Jsont.jsonS.toption;token:string}(* NOTE(dinosaure): [token] is common even if we do a DNS or an HTTP challenge. *)letpp_statusppfs=Fmt.stringppf(matchswith|Pending->"pending"|Processing->"processing"|Valid->"valid"|Invalid->"invalid")letppppfc=Fmt.pfppf"status %a@,typ %a@,token %s@,url %s@,validated %a@,error %a"pp_statusc.statuspp_typc.typc.tokenc.urlFmt.(option~none:(any"no")(Ptime.pp_rfc3339()))c.validatedFmt.(option~none:(any"no error")pp_json)c.errormoduleOptics=structlettyp()=Lun.lense(fun{typ;_}->typ)(funttyp->{twithtyp})leturl()=Lun.lense(fun{url;_}->url)(funturl->{twithurl})letstatus()=Lun.lense(fun{status;_}->status)(funtstatus->{twithstatus})letvalidated()=Lun.lense(fun{validated;_}->validated)(funtvalidated->{twithvalidated})leterror()=Lun.lense(fun{error;_}->error)(funterror->{twitherror})lettoken()=Lun.lense(fun{token;_}->token)(funttoken->{twithtoken})endlett=letopenJsontinlettyp=letenc=Lun.getOptics.typinObject.mem"type"~enctypinleturl=letenc=Lun.getOptics.urlinObject.mem"url"~encstringinletstatus=letenc=Lun.getOptics.statusinObject.mem"status"~encstatusinletvalidated=letenc=Lun.getOptics.validatedinObject.opt_mem"validated"~encrfc3339inleterror=letenc=Lun.getOptics.errorinObject.opt_mem"error"~enc(Object.as_string_mapjson)inlettoken=letenc=Lun.getOptics.tokeninObject.mem"token"~encstringinletfntypurlstatusvalidatederrortoken={typ;url;status;validated;error;token}inObject.mapfn|>typ|>url|>status|>validated|>error|>token|>Object.finishletdecodestr=matchJsont_bytesrw.decode_stringtstrwith|Okt->Okt|Error_->error_msgf"Invalid challenge object"endmoduleAuthorization=structtypestatus=|Pending|Valid|Invalid|Deactivated|Expired|Revokedletstatus=letpending="pending",Pendingandvalid="valid",Validandinvalid="invalid",Invalidanddeactivated="deactivated",Deactivatedandexpired="expired",Expiredandrevoked="revoked",RevokedinJsont.enum[pending;valid;invalid;deactivated;expired;revoked]typet={identifier:string;status:status;expires:Ptime.toption;challenges:Challenge.tlist;wildcard:bool}letpp_statusppfs=Fmt.stringppf(matchswith|Pending->"pending"|Valid->"valid"|Invalid->"invalid"|Deactivated->"deactivated"|Expired->"expired"|Revoked->"revoked")letppppfa=Fmt.pfppf"status %a@,identifier %a@,expires %a@,challenges %a@,wildcard %a"pp_statusa.statuspp_ida.identifierFmt.(option~none:(any"no")(Ptime.pp_rfc3339()))a.expiresFmt.(list~sep:(any",")Challenge.pp)a.challengesFmt.boola.wildcardmoduleOptics=structletidentifier()=Lun.lense(fun{identifier;_}->identifier)(funtidentifier->{twithidentifier})letstatus()=Lun.lense(fun{status;_}->status)(funtstatus->{twithstatus})letexpires()=Lun.lense(fun{expires;_}->expires)(funtexpires->{twithexpires})letchallenges()=Lun.lense(fun{challenges;_}->challenges)(funtchallenges->{twithchallenges})letwildcard()=Lun.lense(fun{wildcard;_}->wildcard)(funtwildcard->{twithwildcard})endlett=letopenJsontinletidentifier=letenc=Lun.getOptics.identifierinObject.mem"identifier"~encstringinletstatus=letenc=Lun.getOptics.statusinObject.mem"status"~encstatusinletexpires=letenc=Lun.getOptics.expiresinObject.opt_mem"expires"~encrfc3339inletchallenges=letenc=Lun.getOptics.challengesinObject.mem"challenges"~enc(listChallenge.t)inletwildcard=letenc=Lun.getOptics.wildcardinletdec_absent=falseinletenc_omit=Fun.negateFun.idinObject.mem"wildcard"~enc~dec_absent~enc_omitboolinletfnidentifierstatusexpireschallengeswildcard={identifier;status;expires;challenges;wildcard}inObject.mapfn|>identifier|>status|>expires|>challenges|>wildcard|>Object.finishletdecodestr=matchJsont_bytesrw.decode_stringtstrwith|Okt->Okt|Error_->error_msgf"Invalid authorization object"endmoduleError=structtypeerror=[`Account_does_not_exist|`Already_revoked|`Bad_csr|`Bad_nonce|`Bad_public_key|`Bad_revocation_reason|`Bad_signature_algorithm|`CAA|`Connection|`DNS|`External_account_required|`Incorrect_response|`Invalid_contact|`Malformed|`Order_not_ready|`Rate_limited|`Rejected_identifier|`Server_internal|`TLS|`Unauthorized|`Unsupported_contact|`Unsupported_identifier|`User_action_required]leterror=["accountDoesNotExist",`Account_does_not_exist;"alreadyRevoked",`Already_revoked;"badCSR",`Bad_csr;"badNonce",`Bad_nonce;"badPublicKey",`Bad_public_key;"badRevocationReason",`Bad_revocation_reason;"badSignatureAlgorithm",`Bad_signature_algorithm;"caa",`CAA;"connection",`Connection;"dns",`DNS;"externalAccountRequired",`External_account_required;"incorrectResponse",`Incorrect_response;"invalidContact",`Invalid_contact;"malformed",`Malformed;"orderNotReady",`Order_not_ready;"rateLimited",`Rate_limited;"rejectedIdentifier",`Rejected_identifier;"serverInternal",`Server_internal;"tls",`TLS;"unauthorized",`Unauthorized;"unsupportedContact",`Unsupported_contact;"unsupportedIdentifier",`Unsupported_identifier;"userActionRequired",`User_action_required]|>List.map(fun(str,value)->"urn:ietf:params:acme:error:"^str,value)|>Jsont.enumtypet={error:error;detail:string}leterr_typ_to_string=function|`Account_does_not_exist->"The request specified an account that does not exist"|`Already_revoked->"The request specified a certificate to be revoked that has already been revoked"|`Bad_csr->"The CSR is unacceptable (e.g., due to a short key)"|`Bad_nonce->"The client sent an unacceptable anti-replay nonce"|`Bad_public_key->"The JWS was signed by a public key the server does not support"|`Bad_revocation_reason->"The revocation reason provided is not allowed by the server"|`Bad_signature_algorithm->"The JWS was signed with an algorithm the server does not support"|`CAA->"Certification Authority Authorization (CAA) records forbid the CA from issuing a certificate"(* | `Compound -> "Specific error conditions are indicated in the 'subproblems' array" *)|`Connection->"The server could not connect to validation target"|`DNS->"There was a problem with a DNS query during identifier validation"|`External_account_required->"The request must include a value for the 'externalAccountBinding' field"|`Incorrect_response->"Response received didn't match the challenge's requirements"|`Invalid_contact->"A contact URL for an account was invalid"|`Malformed->"The request message was malformed"|`Order_not_ready->"The request attempted to finalize an order that is not ready to be finalized"|`Rate_limited->"The request exceeds a rate limit"|`Rejected_identifier->"The server will not issue certificates for the identifier"|`Server_internal->"The server experienced an internal error"|`TLS->"The server received a TLS error during validation"|`Unauthorized->"The client lacks sufficient authorization"|`Unsupported_contact->"A contact URL for an account used an unsupported protocol scheme"|`Unsupported_identifier->"An identifier is of an unsupported type"|`User_action_required->"Visit the 'instance' URL and take actions specified there"letppppfe=Fmt.pfppf"%s, detail: %s"(err_typ_to_stringe.error)e.detailmoduleOptics=structleterror()=Lun.lense(fun{error;_}->error)(funterror->{twitherror})letdetail()=Lun.lense(fun{detail;_}->detail)(funtdetail->{twithdetail})endlett=letopenJsontinleterror=letenc=Lun.getOptics.errorinObject.mem"type"~encerrorinletdetail=letenc=Lun.getOptics.detailinObject.mem"detail"~encstringinObject.map(funerrordetail->{error;detail})|>error|>detail|>Object.finishletdecodestr=matchJsont_bytesrw.decode_stringtstrwith|Okt->Okt|Error_->error_msgf"Invalid error object"end