letsencrypt::Client method getCertificate (public)
<instance of letsencrypt::Client> getCertificate
Defined in /usr/local/ns/tcl/letsencrypt/letsencrypt-procs.tcl
This method does all the steps required to obtain a certificate, such as - selecting the API (production or staging), - registering a new account if necessary, - create public and private key for the account, - issuing a certificate request, - obtaining the certificate, and - installing the certificate. If called interactivaly, the progress is logged to the console, otherwise just into the system log.
- Testcases:
- No testcase defined.
Source code: ns_log notice "letsencrypt client: domains <${:domains}> background ${:background}" if {${:domains} eq ""} { # # Are values for the domains specified in the # NaviServer configuration file? # set :domains [ns_config ns/server/[ns_info server]/module/letsencrypt domains] #ns_log notice "letsencrypt client: domains from NaviServer configuration file: <${:domains}>" } if {${:domains} eq "" && [ns_conn isconnected]} { # # Still no values. Try to get it from the query parameters # #ns_log notice "letsencrypt client: we need a queryget" set :domains [ns_queryget domains ""] ns_log notice "letsencrypt client: domains from query <${:domains}> background ${:background}" # # If the domain names were already submitted in the form # (or via query parameters), we have all data we # need. } ns_log notice "letsencrypt client: domains <${:domains}> background ${:background}" if {${:domains} eq ""} { # # If we have still no values, provide the user with a # form to fill-in the data and to continue from there. # But this works only, when we are not called in the # background. # if {${:background}} { error "letsencrypt: either provide '-domains ...' or run from a connection thread" } ns_log notice "letsencrypt: have to return domainForm" :domainForm return } set :domain [lindex ${:domains} 0] set :sans [lrange ${:domains} 1 end] set config { staging {https://acme-staging-v02.api.letsencrypt.org/directory} production {https://acme-v02.api.letsencrypt.org/directory} } # # Make sure, the sslpath exists # file mkdir ${:sslpath} set :accoutKeyFile ${:sslpath}/letsencrypt-${:API}-account.key ns_log notice "letsencrypt client: call start of report" # # Start output # :startOfReport ns_log notice "letsencrypt: getAPIurls" # # Always get first the API URLs # :getAPIurls $config # # Create or reuse an account # if {[file exists ${:accoutKeyFile}]} { # # We have already registered in the past successfully at # Let's Encrypt and signed the agreement. # :log "Reuse existing account registration at Let's Encrypt (${:accoutKeyFile})<br>" :parseAccountKey :getNonce set payload [subst {{"termsOfServiceAgreed": true, "onlyReturnExisting": true, "contact": \["mailto:webmaster@${:domain}"\]}}] set status [:send_signed_request [:URL newAccount] $payload] if {$status eq "400"} { :abortMsg $status "authorization for existing account failed" return } else { set :kid [ns_set iget ${:replyHeaders} "location"] :log "<pre>registration headers contained kid ${:kid}\n</pre>" } } else { set status [:registerNewAccount] if {$status >= 400} { :abortMsg $status "Registration" return } set status [:signAgreement] if {$status >= 400} { :abortMsg $status "Agreement" return } } # # Create a new order for the domains # file delete -force [ns_server pagedir]/.well-known file mkdir [ns_server pagedir]/.well-known :log "Creating new order...<br>" set ids {} foreach domain ${:domains} { lappend ids [subst {{"type": "dns", "value": "$domain"}}] } set payload [subst {{"identifiers": \[[join $ids ,]\]}}] :log "... payload: <pre>$payload</pre>" set httpStatus [:send_signed_request [:URL newOrder] $payload] if {$httpStatus >= 400} { :abortMsg $httpStatus "Order failed" return } set orderDict [json::json2dict ${:replyText}] set authorizations [dict get $orderDict authorizations] set identifiers [dict get $orderDict identifiers] set orderFinalizeURL [dict get $orderDict finalize] #:log "<pre>authorizations:\n$authorizations\norderFinalizeURL:$orderFinalizeURL</pre>" if {[llength $authorizations] != [llength ${:domains}]} { :abortMsg $httpStatus "number of domains ([llength ${:domains}]) differs from number of authorizations ([llength $authorizations])" return } foreach domain ${:domains} auth_url $authorizations id $identifiers { set status [:authorizeDomain $auth_url [dict get $id value]] if {$status in {invalid}} { :log [ns_trim -delimiter | [subst { |Validation of domain $domain failed (final status $status). |<p>Please issue a corrected certificate check. }]] return } } file delete -force [ns_server pagedir]/.well-known # # Get certificate # set status [:certificateRequest $orderFinalizeURL] if {$status >= 400} { :abortMsg $status "Certificate request" return } # # Install certificate and update configuration file # :certificateInstall :updateConfiguration if {${:API} eq "production"} { # # Everything was updated, We can trigger the reload # operation by sending SIGHUP to the nsd process # ns_kill [pid] 1 :log [ns_trim -delimiter | [subst { |<br>The new certificate is installed and was |reloaded via SIGHUP. For old versions of |NaviServer, restart your NaviServer instance and |check results on |<a href="https://${:domain}">https://${:domain}</a>. |<p> }]] :log "<p>Certificate were reloaded by sending SIGHUP to nsd" } else { :log "<p><strong>Warning:</strong> no automated reloading" "when using the 'staging' environment<p>" }XQL Not present: Generic, PostgreSQL, Oracle