mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-23 22:27:38 -05:00
letsencrypt: Allow (but warn about) empty emails
This commit is contained in:
parent
e99b3af0a5
commit
3843cea959
4 changed files with 37 additions and 9 deletions
|
@ -156,10 +156,6 @@ func groupConfigsByEmail(configs []server.Config) (map[string][]*server.Config,
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
leEmail := getEmail(configs[i])
|
leEmail := getEmail(configs[i])
|
||||||
if leEmail == "" {
|
|
||||||
// TODO: This may not be an error; just a poor choice by the user
|
|
||||||
return nil, errors.New("must have email address to serve HTTPS without existing certificate and key")
|
|
||||||
}
|
|
||||||
initMap[leEmail] = append(initMap[leEmail], &configs[i])
|
initMap[leEmail] = append(initMap[leEmail], &configs[i])
|
||||||
}
|
}
|
||||||
return initMap, nil
|
return initMap, nil
|
||||||
|
|
|
@ -48,12 +48,18 @@ func (s Storage) Users() string {
|
||||||
|
|
||||||
// User gets the account folder for the user with email.
|
// User gets the account folder for the user with email.
|
||||||
func (s Storage) User(email string) string {
|
func (s Storage) User(email string) string {
|
||||||
|
if email == "" {
|
||||||
|
email = emptyEmail
|
||||||
|
}
|
||||||
return filepath.Join(s.Users(), email)
|
return filepath.Join(s.Users(), email)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserRegFile gets the path to the registration file for
|
// UserRegFile gets the path to the registration file for
|
||||||
// the user with the given email address.
|
// the user with the given email address.
|
||||||
func (s Storage) UserRegFile(email string) string {
|
func (s Storage) UserRegFile(email string) string {
|
||||||
|
if email == "" {
|
||||||
|
email = emptyEmail
|
||||||
|
}
|
||||||
fileName := emailUsername(email)
|
fileName := emailUsername(email)
|
||||||
if fileName == "" {
|
if fileName == "" {
|
||||||
fileName = "registration"
|
fileName = "registration"
|
||||||
|
@ -64,7 +70,9 @@ func (s Storage) UserRegFile(email string) string {
|
||||||
// UserKeyFile gets the path to the private key file for
|
// UserKeyFile gets the path to the private key file for
|
||||||
// the user with the given email address.
|
// the user with the given email address.
|
||||||
func (s Storage) UserKeyFile(email string) string {
|
func (s Storage) UserKeyFile(email string) string {
|
||||||
// TODO: Read the KeyFile property in the registration file instead?
|
if email == "" {
|
||||||
|
email = emptyEmail
|
||||||
|
}
|
||||||
fileName := emailUsername(email)
|
fileName := emailUsername(email)
|
||||||
if fileName == "" {
|
if fileName == "" {
|
||||||
fileName = "private"
|
fileName = "private"
|
||||||
|
|
|
@ -35,6 +35,17 @@ func TestStorage(t *testing.T) {
|
||||||
if expected, actual := filepath.Join("letsencrypt", "users", "me@example.com", "me.key"), storage.UserKeyFile("me@example.com"); actual != expected {
|
if expected, actual := filepath.Join("letsencrypt", "users", "me@example.com", "me.key"), storage.UserKeyFile("me@example.com"); actual != expected {
|
||||||
t.Errorf("Expected UserKeyFile() to return '%s' but got '%s'", expected, actual)
|
t.Errorf("Expected UserKeyFile() to return '%s' but got '%s'", expected, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test with empty emails
|
||||||
|
if expected, actual := filepath.Join("letsencrypt", "users", emptyEmail), storage.User(emptyEmail); actual != expected {
|
||||||
|
t.Errorf("Expected User(\"\") to return '%s' but got '%s'", expected, actual)
|
||||||
|
}
|
||||||
|
if expected, actual := filepath.Join("letsencrypt", "users", emptyEmail, emptyEmail+".json"), storage.UserRegFile(""); actual != expected {
|
||||||
|
t.Errorf("Expected UserRegFile(\"\") to return '%s' but got '%s'", expected, actual)
|
||||||
|
}
|
||||||
|
if expected, actual := filepath.Join("letsencrypt", "users", emptyEmail, emptyEmail+".key"), storage.UserKeyFile(""); actual != expected {
|
||||||
|
t.Errorf("Expected UserKeyFile(\"\") to return '%s' but got '%s'", expected, actual)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEmailUsername(t *testing.T) {
|
func TestEmailUsername(t *testing.T) {
|
||||||
|
@ -61,6 +72,10 @@ func TestEmailUsername(t *testing.T) {
|
||||||
input: "@foobar.com",
|
input: "@foobar.com",
|
||||||
expect: "foobar.com",
|
expect: "foobar.com",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
input: emptyEmail,
|
||||||
|
expect: emptyEmail,
|
||||||
|
},
|
||||||
} {
|
} {
|
||||||
if actual := emailUsername(test.input); actual != test.expect {
|
if actual := emailUsername(test.input); actual != test.expect {
|
||||||
t.Errorf("Test %d: Expected username to be '%s' but was '%s'", i, test.expect, actual)
|
t.Errorf("Test %d: Expected username to be '%s' but was '%s'", i, test.expect, actual)
|
||||||
|
|
|
@ -115,6 +115,8 @@ func newUser(email string) (User, error) {
|
||||||
// getEmail does everything it can to obtain an email
|
// getEmail does everything it can to obtain an email
|
||||||
// address from the user to use for TLS for cfg. If it
|
// address from the user to use for TLS for cfg. If it
|
||||||
// cannot get an email address, it returns empty string.
|
// cannot get an email address, it returns empty string.
|
||||||
|
// (It will warn the user of the consequences of an
|
||||||
|
// empty email.)
|
||||||
func getEmail(cfg server.Config) string {
|
func getEmail(cfg server.Config) string {
|
||||||
// First try the tls directive from the Caddyfile
|
// First try the tls directive from the Caddyfile
|
||||||
leEmail := cfg.TLS.LetsEncryptEmail
|
leEmail := cfg.TLS.LetsEncryptEmail
|
||||||
|
@ -124,7 +126,6 @@ func getEmail(cfg server.Config) string {
|
||||||
}
|
}
|
||||||
if leEmail == "" {
|
if leEmail == "" {
|
||||||
// Then try to get most recent user email ~/.caddy/users file
|
// Then try to get most recent user email ~/.caddy/users file
|
||||||
// TODO: Probably better to open the user's json file and read the email out of there...
|
|
||||||
userDirs, err := ioutil.ReadDir(storage.Users())
|
userDirs, err := ioutil.ReadDir(storage.Users())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
var mostRecent os.FileInfo
|
var mostRecent os.FileInfo
|
||||||
|
@ -143,9 +144,13 @@ func getEmail(cfg server.Config) string {
|
||||||
}
|
}
|
||||||
if leEmail == "" {
|
if leEmail == "" {
|
||||||
// Alas, we must bother the user and ask for an email address
|
// Alas, we must bother the user and ask for an email address
|
||||||
// TODO/BUG: This doesn't work when Caddyfile is piped into caddy
|
|
||||||
reader := bufio.NewReader(stdin)
|
reader := bufio.NewReader(stdin)
|
||||||
fmt.Print("Email address: ") // TODO: More explanation probably, and show ToS?
|
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(" <TODO: link>")
|
||||||
|
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.Print("Email address: ")
|
||||||
var err error
|
var err error
|
||||||
leEmail, err = reader.ReadString('\n')
|
leEmail, err = reader.ReadString('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -169,7 +174,7 @@ func promptUserAgreement(agreementURL string, changed bool) bool {
|
||||||
fmt.Print("Do you agree to the terms? (y/n): ")
|
fmt.Print("Do you agree to the terms? (y/n): ")
|
||||||
}
|
}
|
||||||
|
|
||||||
reader := bufio.NewReader(stdin) // TODO/BUG: This doesn't work when Caddyfile is piped into caddy
|
reader := bufio.NewReader(stdin)
|
||||||
answer, err := reader.ReadString('\n')
|
answer, err := reader.ReadString('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
|
@ -182,3 +187,7 @@ func promptUserAgreement(agreementURL string, changed bool) bool {
|
||||||
// stdin is used to read the user's input if prompted;
|
// stdin is used to read the user's input if prompted;
|
||||||
// this is changed by tests during tests.
|
// this is changed by tests during tests.
|
||||||
var stdin = io.ReadWriter(os.Stdin)
|
var stdin = io.ReadWriter(os.Stdin)
|
||||||
|
|
||||||
|
// The name of the folder for accounts where the email
|
||||||
|
// address was not provided; default 'username' if you will.
|
||||||
|
const emptyEmail = "default"
|
||||||
|
|
Loading…
Reference in a new issue