mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-23 22:27:38 -05:00
letsencrypt: Re-prompt user if obtaining certs fails due to updated SA
This commit is contained in:
parent
2712dcd1f5
commit
be0fb0053d
3 changed files with 45 additions and 10 deletions
|
@ -7,7 +7,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -84,11 +83,35 @@ func Activate(configs []server.Config) ([]server.Config, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// client is ready, so let's get free, trusted SSL certificates! yeah!
|
// client is ready, so let's get free, trusted SSL certificates! yeah!
|
||||||
|
Obtain:
|
||||||
certificates, failures := obtainCertificates(client, serverConfigs)
|
certificates, failures := obtainCertificates(client, serverConfigs)
|
||||||
if len(failures) > 0 {
|
if len(failures) > 0 {
|
||||||
for k, v := range failures {
|
// Build an error string to return, using all the failures in the list.
|
||||||
log.Printf("[%s] Failed to get a certificate: %s", k, v)
|
var errMsg string
|
||||||
|
|
||||||
|
// An agreement error means we need to prompt the user (once) with updated terms
|
||||||
|
// while they're still here.
|
||||||
|
var promptedUpdatedTerms bool
|
||||||
|
|
||||||
|
for domain, obtainErr := range failures {
|
||||||
|
// If the failure was simply because the terms have changed, re-prompt and re-try
|
||||||
|
if tosErr, ok := obtainErr.(acme.TOSError); ok && !promptedUpdatedTerms {
|
||||||
|
Agreed = promptUserAgreement(tosErr.Detail, true) // TODO: Use latest URL
|
||||||
|
promptedUpdatedTerms = true
|
||||||
|
if Agreed {
|
||||||
|
err := client.AgreeToTOS()
|
||||||
|
if err != nil {
|
||||||
|
return configs, errors.New("error agreeing to updated terms: " + err.Error())
|
||||||
|
}
|
||||||
|
goto Obtain
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If user did not agree or it was any other kind of error, just append to the list of errors
|
||||||
|
errMsg += "[" + domain + "] failed to get certificate: " + obtainErr.Error() + "\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return configs, errors.New(errMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ... that's it. save the certs, keys, and metadata files to disk
|
// ... that's it. save the certs, keys, and metadata files to disk
|
||||||
|
@ -213,7 +236,7 @@ func newClient(leEmail string) (*acme.Client, error) {
|
||||||
leUser.Registration = reg
|
leUser.Registration = reg
|
||||||
|
|
||||||
if !Agreed && reg.TosURL == "" {
|
if !Agreed && reg.TosURL == "" {
|
||||||
Agreed = promptUserAgreement("<TODO>", false) // TODO
|
Agreed = promptUserAgreement(saURL, false) // TODO - latest URL
|
||||||
}
|
}
|
||||||
if !Agreed && reg.TosURL == "" {
|
if !Agreed && reg.TosURL == "" {
|
||||||
return nil, errors.New("user must agree to terms")
|
return nil, errors.New("user must agree to terms")
|
||||||
|
|
|
@ -97,8 +97,8 @@ func renewCertificates(configs []server.Config) (int, []error) {
|
||||||
// Directly convert it to days for the following checks.
|
// Directly convert it to days for the following checks.
|
||||||
daysLeft := int(expTime.Sub(time.Now().UTC()).Hours() / 24)
|
daysLeft := int(expTime.Sub(time.Now().UTC()).Hours() / 24)
|
||||||
|
|
||||||
// Renew with a week or less remaining.
|
// Renew with two weeks or less remaining.
|
||||||
if daysLeft <= 7 {
|
if daysLeft <= 14 {
|
||||||
log.Printf("[INFO] There are %d days left on the certificate of %s. Trying to renew now.", daysLeft, cfg.Host)
|
log.Printf("[INFO] There are %d days left on the certificate of %s. Trying to renew now.", daysLeft, cfg.Host)
|
||||||
client, err := newClient("") // email not used for renewal
|
client, err := newClient("") // email not used for renewal
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -127,8 +127,17 @@ func renewCertificates(configs []server.Config) (int, []error) {
|
||||||
// Renew certificate.
|
// Renew certificate.
|
||||||
// TODO: revokeOld should be an option in the caddyfile
|
// TODO: revokeOld should be an option in the caddyfile
|
||||||
// TODO: bundle should be an option in the caddyfile as well :)
|
// TODO: bundle should be an option in the caddyfile as well :)
|
||||||
|
Renew:
|
||||||
newCertMeta, err := client.RenewCertificate(certMeta, true, true)
|
newCertMeta, err := client.RenewCertificate(certMeta, true, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if _, ok := err.(acme.TOSError); ok {
|
||||||
|
err := client.AgreeToTOS()
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
goto Renew
|
||||||
|
}
|
||||||
|
|
||||||
time.Sleep(10 * time.Second)
|
time.Sleep(10 * time.Second)
|
||||||
newCertMeta, err = client.RenewCertificate(certMeta, true, true)
|
newCertMeta, err = client.RenewCertificate(certMeta, true, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -146,9 +146,9 @@ func getEmail(cfg server.Config) string {
|
||||||
reader := bufio.NewReader(stdin)
|
reader := bufio.NewReader(stdin)
|
||||||
fmt.Println("Your sites will be served over HTTPS automatically using Let's Encrypt.")
|
fmt.Println("Your sites will be served over HTTPS automatically using Let's Encrypt.")
|
||||||
fmt.Println("By continuing, you agree to the Let's Encrypt Subscriber Agreement at:")
|
fmt.Println("By continuing, you agree to the Let's Encrypt Subscriber Agreement at:")
|
||||||
fmt.Println(" https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf") // TODO: Show current SA link
|
fmt.Println(" " + saURL) // TODO: Show current SA link
|
||||||
fmt.Println("Please enter your email address so you can recover your account if needed.")
|
fmt.Println("Please enter your email address so you can recover your account if needed.")
|
||||||
fmt.Println("You can leave it blank, but you lose the ability to recover your account.")
|
fmt.Println("You can leave it blank, but you'll lose the ability to recover your account.")
|
||||||
fmt.Print("Email address: ")
|
fmt.Print("Email address: ")
|
||||||
var err error
|
var err error
|
||||||
leEmail, err = reader.ReadString('\n')
|
leEmail, err = reader.ReadString('\n')
|
||||||
|
@ -167,10 +167,10 @@ func getEmail(cfg server.Config) string {
|
||||||
// agreeing, pass false. It returns whether the user agreed or not.
|
// agreeing, pass false. It returns whether the user agreed or not.
|
||||||
func promptUserAgreement(agreementURL string, changed bool) bool {
|
func promptUserAgreement(agreementURL string, changed bool) bool {
|
||||||
if changed {
|
if changed {
|
||||||
fmt.Printf("The Let's Encrypt Subscriber Agreement has changed:\n%s\n", agreementURL)
|
fmt.Printf("The Let's Encrypt Subscriber Agreement has changed:\n %s\n", agreementURL)
|
||||||
fmt.Print("Do you agree to the new terms? (y/n): ")
|
fmt.Print("Do you agree to the new terms? (y/n): ")
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("To continue, you must agree to the Let's Encrypt Subscriber Agreement:\n%s\n", agreementURL)
|
fmt.Printf("To continue, you must agree to the Let's Encrypt Subscriber Agreement:\n %s\n", agreementURL)
|
||||||
fmt.Print("Do you agree to the terms? (y/n): ")
|
fmt.Print("Do you agree to the terms? (y/n): ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,3 +191,6 @@ var stdin = io.ReadWriter(os.Stdin)
|
||||||
// The name of the folder for accounts where the email
|
// The name of the folder for accounts where the email
|
||||||
// address was not provided; default 'username' if you will.
|
// address was not provided; default 'username' if you will.
|
||||||
const emptyEmail = "default"
|
const emptyEmail = "default"
|
||||||
|
|
||||||
|
// TODO: Use latest
|
||||||
|
const saURL = "https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf"
|
||||||
|
|
Loading…
Reference in a new issue