Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
caddy
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
caddy
Commits
a3a82657
Commit
a3a82657
authored
Oct 17, 2015
by
Matthew Holt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor letsencrypt code into its own package
parent
307c2ffe
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
318 additions
and
168 deletions
+318
-168
config/config.go
config/config.go
+2
-7
config/letsencrypt/crypto.go
config/letsencrypt/crypto.go
+43
-0
config/letsencrypt/letsencrypt.go
config/letsencrypt/letsencrypt.go
+45
-159
config/letsencrypt/storage.go
config/letsencrypt/storage.go
+128
-0
config/letsencrypt/user.go
config/letsencrypt/user.go
+97
-0
main.go
main.go
+3
-2
No files found.
config/config.go
View file @
a3a82657
...
@@ -8,6 +8,7 @@ import (
...
@@ -8,6 +8,7 @@ import (
"sync"
"sync"
"github.com/mholt/caddy/app"
"github.com/mholt/caddy/app"
"github.com/mholt/caddy/config/letsencrypt"
"github.com/mholt/caddy/config/parse"
"github.com/mholt/caddy/config/parse"
"github.com/mholt/caddy/config/setup"
"github.com/mholt/caddy/config/setup"
"github.com/mholt/caddy/middleware"
"github.com/mholt/caddy/middleware"
...
@@ -102,7 +103,7 @@ func Load(filename string, input io.Reader) (Group, error) {
...
@@ -102,7 +103,7 @@ func Load(filename string, input io.Reader) (Group, error) {
log
.
SetFlags
(
flags
)
log
.
SetFlags
(
flags
)
// secure all the things
// secure all the things
configs
,
err
=
initiateLetsEncrypt
(
configs
)
configs
,
err
=
letsencrypt
.
Activate
(
configs
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
...
@@ -272,12 +273,6 @@ var (
...
@@ -272,12 +273,6 @@ var (
// Site port
// Site port
Port
=
DefaultPort
Port
=
DefaultPort
// Let's Encrypt account email
LetsEncryptEmail
string
// Agreement to Let's Encrypt terms
LetsEncryptAgree
bool
)
)
// Group maps network addresses to their configurations.
// Group maps network addresses to their configurations.
...
...
config/letsencrypt/crypto.go
0 → 100644
View file @
a3a82657
package
letsencrypt
import
(
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"io/ioutil"
"os"
)
// saveCertificate saves a DER-encoded (binary format) certificate
// to file.
func
saveCertificate
(
certBytes
[]
byte
,
file
string
)
error
{
pemCert
:=
pem
.
Block
{
Type
:
"CERTIFICATE"
,
Bytes
:
certBytes
}
certOut
,
err
:=
os
.
Create
(
file
)
if
err
!=
nil
{
return
err
}
pem
.
Encode
(
certOut
,
&
pemCert
)
certOut
.
Close
()
return
nil
}
// loadRSAPrivateKey loads a PEM-encoded RSA private key from file.
func
loadRSAPrivateKey
(
file
string
)
(
*
rsa
.
PrivateKey
,
error
)
{
keyBytes
,
err
:=
ioutil
.
ReadFile
(
file
)
if
err
!=
nil
{
return
nil
,
err
}
keyBlock
,
_
:=
pem
.
Decode
(
keyBytes
)
return
x509
.
ParsePKCS1PrivateKey
(
keyBlock
.
Bytes
)
}
// saveRSAPrivateKey saves a PEM-encoded RSA private key to file.
func
saveRSAPrivateKey
(
key
*
rsa
.
PrivateKey
,
file
string
)
error
{
pemKey
:=
pem
.
Block
{
Type
:
"RSA PRIVATE KEY"
,
Bytes
:
x509
.
MarshalPKCS1PrivateKey
(
key
)}
keyOut
,
err
:=
os
.
Create
(
file
)
if
err
!=
nil
{
return
err
}
defer
keyOut
.
Close
()
return
pem
.
Encode
(
keyOut
,
&
pemKey
)
}
config/letsencrypt.go
→
config/letsencrypt
/letsencrypt
.go
View file @
a3a82657
package
config
package
letsencrypt
// TODO: This code is a mess but I'm cleaning it up locally and
// refactoring a bunch. It will have tests, too. Don't worry. :)
import
(
import
(
"bufio"
"bufio"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/json"
"encoding/json"
"encoding/pem"
"errors"
"errors"
"fmt"
"fmt"
"io/ioutil"
"io/ioutil"
"net/http"
"net/http"
"os"
"os"
"path/filepath"
"strings"
"strings"
"github.com/mholt/caddy/app"
"github.com/mholt/caddy/middleware"
"github.com/mholt/caddy/middleware"
"github.com/mholt/caddy/middleware/redirect"
"github.com/mholt/caddy/middleware/redirect"
"github.com/mholt/caddy/server"
"github.com/mholt/caddy/server"
"github.com/xenolf/lego/acme"
"github.com/xenolf/lego/acme"
)
)
// Some essential values related to the Let's Encrypt process
// Activate sets up TLS for each server config in configs
const
(
// as needed. It only skips the config if the cert and key
// Size of RSA keys in bits
// are already provided or if plaintext http is explicitly
rsaKeySize
=
2048
// specified as the port.
func
Activate
(
configs
[]
server
.
Config
)
([]
server
.
Config
,
error
)
{
// The base URL to the Let's Encrypt CA
caURL
=
"http://192.168.99.100:4000"
// The port to expose to the CA server for Simple HTTP Challenge
exposePort
=
"5001"
)
// initiateLetsEncrypt sets up TLS for each server config
// in configs as needed. It only skips the config if the
// cert and key are already specified or if plaintext http
// is explicitly specified as the port.
func
initiateLetsEncrypt
(
configs
[]
server
.
Config
)
([]
server
.
Config
,
error
)
{
// populate map of email address to server configs that use that email address for TLS.
// populate map of email address to server configs that use that email address for TLS.
// this will help us reduce roundtrips when getting the certs.
// this will help us reduce roundtrips when getting the certs.
initMap
:=
make
(
map
[
string
][]
*
server
.
Config
)
initMap
:=
make
(
map
[
string
][]
*
server
.
Config
)
...
@@ -59,7 +38,7 @@ func initiateLetsEncrypt(configs []server.Config) ([]server.Config, error) {
...
@@ -59,7 +38,7 @@ func initiateLetsEncrypt(configs []server.Config) ([]server.Config, error) {
// than one certificate per email address, and still save them individually.
// than one certificate per email address, and still save them individually.
for
leEmail
,
serverConfigs
:=
range
initMap
{
for
leEmail
,
serverConfigs
:=
range
initMap
{
// Look up or create the LE user account
// Look up or create the LE user account
leUser
,
err
:=
get
LetsEncrypt
User
(
leEmail
)
leUser
,
err
:=
getUser
(
leEmail
)
if
err
!=
nil
{
if
err
!=
nil
{
return
configs
,
err
return
configs
,
err
}
}
...
@@ -79,11 +58,11 @@ func initiateLetsEncrypt(configs []server.Config) ([]server.Config, error) {
...
@@ -79,11 +58,11 @@ func initiateLetsEncrypt(configs []server.Config) ([]server.Config, error) {
// TODO: we can just do the agreement once, when registering, right?
// TODO: we can just do the agreement once, when registering, right?
err
=
client
.
AgreeToTos
()
err
=
client
.
AgreeToTos
()
if
err
!=
nil
{
if
err
!=
nil
{
save
LetsEncrypt
User
(
leUser
)
// TODO: Might as well try, right? Error check?
saveUser
(
leUser
)
// TODO: Might as well try, right? Error check?
return
configs
,
errors
.
New
(
"error agreeing to terms: "
+
err
.
Error
())
return
configs
,
errors
.
New
(
"error agreeing to terms: "
+
err
.
Error
())
}
}
err
=
save
LetsEncrypt
User
(
leUser
)
err
=
saveUser
(
leUser
)
if
err
!=
nil
{
if
err
!=
nil
{
return
configs
,
errors
.
New
(
"could not save user: "
+
err
.
Error
())
return
configs
,
errors
.
New
(
"could not save user: "
+
err
.
Error
())
}
}
...
@@ -103,17 +82,16 @@ func initiateLetsEncrypt(configs []server.Config) ([]server.Config, error) {
...
@@ -103,17 +82,16 @@ func initiateLetsEncrypt(configs []server.Config) ([]server.Config, error) {
// ... that's it. save the certs, keys, and update server configs.
// ... that's it. save the certs, keys, and update server configs.
for
_
,
cert
:=
range
certificates
{
for
_
,
cert
:=
range
certificates
{
certFolder
:=
filepath
.
Join
(
app
.
DataFolder
(),
"letsencrypt"
,
"sites"
,
cert
.
Domain
)
os
.
MkdirAll
(
storage
.
Site
(
cert
.
Domain
),
0700
)
os
.
MkdirAll
(
certFolder
,
0700
)
// Save cert
// Save cert
err
=
saveCertificate
(
cert
.
Certificate
,
filepath
.
Join
(
certFolder
,
cert
.
Domain
+
".crt"
))
err
=
saveCertificate
(
cert
.
Certificate
,
storage
.
SiteCertFile
(
cert
.
Domain
))
if
err
!=
nil
{
if
err
!=
nil
{
return
configs
,
err
return
configs
,
err
}
}
// Save private key
// Save private key
err
=
ioutil
.
WriteFile
(
filepath
.
Join
(
certFolder
,
cert
.
Domain
+
".key"
),
cert
.
PrivateKey
,
0600
)
err
=
ioutil
.
WriteFile
(
storage
.
SiteKeyFile
(
cert
.
Domain
),
cert
.
PrivateKey
,
0600
)
if
err
!=
nil
{
if
err
!=
nil
{
return
configs
,
err
return
configs
,
err
}
}
...
@@ -123,7 +101,7 @@ func initiateLetsEncrypt(configs []server.Config) ([]server.Config, error) {
...
@@ -123,7 +101,7 @@ func initiateLetsEncrypt(configs []server.Config) ([]server.Config, error) {
if
err
!=
nil
{
if
err
!=
nil
{
return
configs
,
err
return
configs
,
err
}
}
err
=
ioutil
.
WriteFile
(
filepath
.
Join
(
certFolder
,
cert
.
Domain
+
".json"
),
jsonBytes
,
0600
)
err
=
ioutil
.
WriteFile
(
storage
.
SiteMetaFile
(
cert
.
Domain
),
jsonBytes
,
0600
)
if
err
!=
nil
{
if
err
!=
nil
{
return
configs
,
err
return
configs
,
err
}
}
...
@@ -131,8 +109,8 @@ func initiateLetsEncrypt(configs []server.Config) ([]server.Config, error) {
...
@@ -131,8 +109,8 @@ func initiateLetsEncrypt(configs []server.Config) ([]server.Config, error) {
// it all comes down to this: filling in the file path of a valid certificate automatically
// it all comes down to this: filling in the file path of a valid certificate automatically
for
_
,
cfg
:=
range
serverConfigs
{
for
_
,
cfg
:=
range
serverConfigs
{
cfg
.
TLS
.
Certificate
=
filepath
.
Join
(
app
.
DataFolder
(),
"letsencrypt"
,
"sites"
,
cfg
.
Host
,
cfg
.
Host
+
".crt"
)
cfg
.
TLS
.
Certificate
=
storage
.
SiteCertFile
(
cfg
.
Host
)
cfg
.
TLS
.
Key
=
filepath
.
Join
(
app
.
DataFolder
(),
"letsencrypt"
,
"sites"
,
cfg
.
Host
,
cfg
.
Host
+
".key"
)
cfg
.
TLS
.
Key
=
storage
.
SiteKeyFile
(
cfg
.
Host
)
cfg
.
TLS
.
Enabled
=
true
cfg
.
TLS
.
Enabled
=
true
cfg
.
Port
=
"https"
cfg
.
Port
=
"https"
...
@@ -188,12 +166,12 @@ func getEmail(cfg server.Config) string {
...
@@ -188,12 +166,12 @@ func getEmail(cfg server.Config) string {
leEmail
:=
cfg
.
TLS
.
LetsEncryptEmail
leEmail
:=
cfg
.
TLS
.
LetsEncryptEmail
if
leEmail
==
""
{
if
leEmail
==
""
{
// Then try memory (command line flag or typed by user previously)
// Then try memory (command line flag or typed by user previously)
leEmail
=
LetsEncryp
tEmail
leEmail
=
Defaul
tEmail
}
}
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...
// TODO: Probably better to open the user's json file and read the email out of there...
userDirs
,
err
:=
ioutil
.
ReadDir
(
filepath
.
Join
(
app
.
DataFolder
(),
"letsencrypt"
,
"users"
))
userDirs
,
err
:=
ioutil
.
ReadDir
(
storage
.
Users
(
))
if
err
==
nil
{
if
err
==
nil
{
var
mostRecent
os
.
FileInfo
var
mostRecent
os
.
FileInfo
for
_
,
dir
:=
range
userDirs
{
for
_
,
dir
:=
range
userDirs
{
...
@@ -204,9 +182,11 @@ func getEmail(cfg server.Config) string {
...
@@ -204,9 +182,11 @@ func getEmail(cfg server.Config) string {
mostRecent
=
dir
mostRecent
=
dir
}
}
}
}
if
mostRecent
!=
nil
{
leEmail
=
mostRecent
.
Name
()
leEmail
=
mostRecent
.
Name
()
}
}
}
}
}
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
reader
:=
bufio
.
NewReader
(
os
.
Stdin
)
reader
:=
bufio
.
NewReader
(
os
.
Stdin
)
...
@@ -216,135 +196,41 @@ func getEmail(cfg server.Config) string {
...
@@ -216,135 +196,41 @@ func getEmail(cfg server.Config) string {
if
err
!=
nil
{
if
err
!=
nil
{
return
""
return
""
}
}
LetsEncryp
tEmail
=
leEmail
Defaul
tEmail
=
leEmail
}
}
return
strings
.
TrimSpace
(
leEmail
)
return
strings
.
TrimSpace
(
leEmail
)
}
}
func
saveLetsEncryptUser
(
user
LetsEncryptUser
)
error
{
var
(
// make user account folder
// Let's Encrypt account email to use if none provided
userFolder
:=
filepath
.
Join
(
app
.
DataFolder
(),
"letsencrypt"
,
"users"
,
user
.
Email
)
DefaultEmail
string
err
:=
os
.
MkdirAll
(
userFolder
,
0700
)
if
err
!=
nil
{
return
err
}
// save private key file
user
.
KeyFile
=
filepath
.
Join
(
userFolder
,
emailUsername
(
user
.
Email
)
+
".key"
)
err
=
savePrivateKey
(
user
.
key
,
user
.
KeyFile
)
if
err
!=
nil
{
return
err
}
// save registration file
jsonBytes
,
err
:=
json
.
MarshalIndent
(
&
user
,
""
,
"
\t
"
)
if
err
!=
nil
{
return
err
}
return
ioutil
.
WriteFile
(
filepath
.
Join
(
userFolder
,
"registration.json"
),
jsonBytes
,
0600
)
}
func
getLetsEncryptUser
(
email
string
)
(
LetsEncryptUser
,
error
)
{
var
user
LetsEncryptUser
userFolder
:=
filepath
.
Join
(
app
.
DataFolder
(),
"letsencrypt"
,
"users"
,
email
)
regFile
,
err
:=
os
.
Open
(
filepath
.
Join
(
userFolder
,
"registration.json"
))
if
err
!=
nil
{
if
os
.
IsNotExist
(
err
)
{
// create a new user
return
newLetsEncryptUser
(
email
)
}
return
user
,
err
}
err
=
json
.
NewDecoder
(
regFile
)
.
Decode
(
&
user
)
if
err
!=
nil
{
return
user
,
err
}
user
.
key
,
err
=
loadPrivateKey
(
user
.
KeyFile
)
if
err
!=
nil
{
return
user
,
err
}
return
user
,
nil
}
func
newLetsEncryptUser
(
email
string
)
(
LetsEncryptUser
,
error
)
{
user
:=
LetsEncryptUser
{
Email
:
email
}
privateKey
,
err
:=
rsa
.
GenerateKey
(
rand
.
Reader
,
rsaKeySize
)
if
err
!=
nil
{
return
user
,
errors
.
New
(
"error generating private key: "
+
err
.
Error
())
}
user
.
key
=
privateKey
return
user
,
nil
}
func
emailUsername
(
email
string
)
string
{
// Whether user has agreed to the Let's Encrypt SA
at
:=
strings
.
Index
(
email
,
"@"
)
Agreed
bool
if
at
==
-
1
{
)
return
email
}
return
email
[
:
at
]
}
type
LetsEncryptUser
struct
{
// Some essential values related to the Let's Encrypt process
Email
string
const
(
Registration
*
acme
.
RegistrationResource
// Size of RSA keys in bits
KeyFile
string
rsaKeySize
=
2048
key
*
rsa
.
PrivateKey
}
func
(
u
LetsEncryptUser
)
GetEmail
()
string
{
// The base URL to the Let's Encrypt CA
return
u
.
Email
caURL
=
"http://192.168.99.100:4000"
}
func
(
u
LetsEncryptUser
)
GetRegistration
()
*
acme
.
RegistrationResource
{
return
u
.
Registration
}
func
(
u
LetsEncryptUser
)
GetPrivateKey
()
*
rsa
.
PrivateKey
{
return
u
.
key
}
// savePrivateKey saves an RSA private key to file.
// The port to expose to the CA server for Simple HTTP Challenge
//
exposePort
=
"5001"
// Borrowed from Sebastian Erhart
)
// https://github.com/xenolf/lego/blob/34910bd541315993224af1f04f9b2877513e5477/crypto.go
func
savePrivateKey
(
key
*
rsa
.
PrivateKey
,
file
string
)
error
{
pemKey
:=
pem
.
Block
{
Type
:
"RSA PRIVATE KEY"
,
Bytes
:
x509
.
MarshalPKCS1PrivateKey
(
key
)}
keyOut
,
err
:=
os
.
Create
(
file
)
if
err
!=
nil
{
return
err
}
pem
.
Encode
(
keyOut
,
&
pemKey
)
keyOut
.
Close
()
return
nil
}
// TODO: Check file permission
// KeySize represents the length of a key in bits
func
saveCertificate
(
certBytes
[]
byte
,
file
string
)
error
{
type
KeySize
int
pemCert
:=
pem
.
Block
{
Type
:
"CERTIFICATE"
,
Bytes
:
certBytes
}
certOut
,
err
:=
os
.
Create
(
file
)
if
err
!=
nil
{
return
err
}
pem
.
Encode
(
certOut
,
&
pemCert
)
certOut
.
Close
()
return
nil
}
// loadPrivateKey loads an RSA private key from filename.
// Key sizes
//
const
(
// Borrowed from Sebastian Erhart
ECC_224
KeySize
=
224
// https://github.com/xenolf/lego/blob/34910bd541315993224af1f04f9b2877513e5477/crypto.go
ECC_256
=
256
func
loadPrivateKey
(
file
string
)
(
*
rsa
.
PrivateKey
,
error
)
{
RSA_2048
=
2048
keyBytes
,
err
:=
ioutil
.
ReadFile
(
file
)
RSA_4096
=
4096
if
err
!=
nil
{
)
return
nil
,
err
}
keyBlock
,
_
:=
pem
.
Decode
(
keyBytes
)
return
x509
.
ParsePKCS1PrivateKey
(
keyBlock
.
Bytes
)
}
type
CertificateMeta
struct
{
type
CertificateMeta
struct
{
Domain
,
URL
string
Domain
,
URL
string
...
...
config/letsencrypt/storage.go
0 → 100644
View file @
a3a82657
package
letsencrypt
import
(
"path/filepath"
"strings"
"github.com/mholt/caddy/app"
)
// storage is used to get file paths in a consistent,
// cross-platform way for persisting Let's Encrypt assets
// on the file system.
var
storage
=
Storage
(
filepath
.
Join
(
app
.
DataFolder
(),
"letsencrypt"
))
// Storage is a root directory and facilitates
// forming file paths derived from it.
type
Storage
string
func
(
s
Storage
)
Path
(
parts
...
string
)
string
{
return
filepath
.
Join
(
append
([]
string
{
string
(
s
)},
parts
...
)
...
)
}
// Sites gets the directory that stores site certificate and keys.
func
(
s
Storage
)
Sites
()
string
{
return
filepath
.
Join
(
string
(
s
),
"sites"
)
}
// Site returns the path to the folder containing assets for domain.
func
(
s
Storage
)
Site
(
domain
string
)
string
{
return
filepath
.
Join
(
s
.
Sites
(),
domain
)
}
// CertFile returns the path to the certificate file for domain.
func
(
s
Storage
)
SiteCertFile
(
domain
string
)
string
{
return
filepath
.
Join
(
s
.
Site
(
domain
),
domain
+
".crt"
)
}
// SiteKeyFile returns the path to domain's private key file.
func
(
s
Storage
)
SiteKeyFile
(
domain
string
)
string
{
return
filepath
.
Join
(
s
.
Site
(
domain
),
domain
+
".key"
)
}
// SiteMetaFile returns the path to the domain's asset metadata file.
func
(
s
Storage
)
SiteMetaFile
(
domain
string
)
string
{
return
filepath
.
Join
(
s
.
Site
(
domain
),
domain
+
".json"
)
}
// Users gets the directory that stores account folders.
func
(
s
Storage
)
Users
()
string
{
return
filepath
.
Join
(
string
(
s
),
"users"
)
}
// User gets the account folder for the user with email.
func
(
s
Storage
)
User
(
email
string
)
string
{
return
filepath
.
Join
(
s
.
Users
(),
email
)
}
// UserRegFile gets the path to the registration file for
// the user with the given email address.
func
(
s
Storage
)
UserRegFile
(
email
string
)
string
{
fileName
:=
emailUsername
(
email
)
if
fileName
==
""
{
fileName
=
"registration"
}
return
filepath
.
Join
(
s
.
User
(
email
),
fileName
+
".json"
)
}
// UserKeyFile gets the path to the private key file for
// the user with the given email address.
func
(
s
Storage
)
UserKeyFile
(
email
string
)
string
{
// TODO: Read the KeyFile property in the registration file instead?
fileName
:=
emailUsername
(
email
)
if
fileName
==
""
{
fileName
=
"private"
}
return
filepath
.
Join
(
s
.
User
(
email
),
fileName
+
".key"
)
}
// emailUsername returns the username portion of an
// email address (part before '@') or the original
// input if it can't find the "@" symbol.
func
emailUsername
(
email
string
)
string
{
at
:=
strings
.
Index
(
email
,
"@"
)
if
at
==
-
1
{
return
email
}
return
email
[
:
at
]
}
/*
// StorageDir is the full path to the folder where this Let's
// Encrypt client will set up camp. In other words, where it
// stores user account information, keys, and certificates.
// All files will be contained in a 'letsencrypt' folder
// within StorageDir.
//
// Changing this after the program has accessed this folder
// will result in undefined behavior.
var StorageDir = "."
// Values related to persisting things on the file system
const (
// ContainerDir is the name of the folder within StorageDir
// in which files or folders are placed.
ContainerDir = "letsencrypt"
// File that contains information about the user's LE account
UserRegistrationFile = "registration.json"
)
// BaseDir returns the full path to the base directory in which
// files or folders may be placed, e.g. "<StorageDir>/letsencrypt".
func BaseDir() string {
return filepath.Join(StorageDir, ContainerDir)
}
// AccountsDir returns the full path to the directory where account
// information is stored for LE users.
func AccountsDir() string {
return filepath.Join(BaseDir(), "users")
}
// AccountsDir gets the full path to the directory for a certain
// user with the email address email.
func AccountDir(email string) string {
return filepath.Join(AccountsDir(), email)
}
*/
config/letsencrypt/user.go
0 → 100644
View file @
a3a82657
package
letsencrypt
import
(
"crypto/rand"
"crypto/rsa"
"encoding/json"
"errors"
"io/ioutil"
"os"
"github.com/xenolf/lego/acme"
)
type
User
struct
{
Email
string
Registration
*
acme
.
RegistrationResource
KeyFile
string
key
*
rsa
.
PrivateKey
}
func
(
u
User
)
GetEmail
()
string
{
return
u
.
Email
}
func
(
u
User
)
GetRegistration
()
*
acme
.
RegistrationResource
{
return
u
.
Registration
}
func
(
u
User
)
GetPrivateKey
()
*
rsa
.
PrivateKey
{
return
u
.
key
}
// getUser loads the user with the given email from disk.
func
getUser
(
email
string
)
(
User
,
error
)
{
var
user
User
// open user file
regFile
,
err
:=
os
.
Open
(
storage
.
UserRegFile
(
email
))
if
err
!=
nil
{
if
os
.
IsNotExist
(
err
)
{
// create a new user
return
newUser
(
email
)
}
return
user
,
err
}
defer
regFile
.
Close
()
// load user information
err
=
json
.
NewDecoder
(
regFile
)
.
Decode
(
&
user
)
if
err
!=
nil
{
return
user
,
err
}
// load their private key
user
.
key
,
err
=
loadRSAPrivateKey
(
user
.
KeyFile
)
if
err
!=
nil
{
return
user
,
err
}
return
user
,
nil
}
// saveUser persists a user's key and account registration
// to the file system.
func
saveUser
(
user
User
)
error
{
// make user account folder
err
:=
os
.
MkdirAll
(
storage
.
User
(
user
.
Email
),
0700
)
if
err
!=
nil
{
return
err
}
// save private key file
user
.
KeyFile
=
storage
.
UserKeyFile
(
user
.
Email
)
err
=
saveRSAPrivateKey
(
user
.
key
,
user
.
KeyFile
)
if
err
!=
nil
{
return
err
}
// save registration file
jsonBytes
,
err
:=
json
.
MarshalIndent
(
&
user
,
""
,
"
\t
"
)
if
err
!=
nil
{
return
err
}
return
ioutil
.
WriteFile
(
storage
.
UserRegFile
(
user
.
Email
),
jsonBytes
,
0600
)
}
// newUser creates a new User for the given email address
// with a new private key. This function does not register
// the user via ACME.
func
newUser
(
email
string
)
(
User
,
error
)
{
user
:=
User
{
Email
:
email
}
privateKey
,
err
:=
rsa
.
GenerateKey
(
rand
.
Reader
,
rsaKeySize
)
if
err
!=
nil
{
return
user
,
errors
.
New
(
"error generating private key: "
+
err
.
Error
())
}
user
.
key
=
privateKey
return
user
,
nil
}
main.go
View file @
a3a82657
...
@@ -15,6 +15,7 @@ import (
...
@@ -15,6 +15,7 @@ import (
"github.com/mholt/caddy/app"
"github.com/mholt/caddy/app"
"github.com/mholt/caddy/config"
"github.com/mholt/caddy/config"
"github.com/mholt/caddy/config/letsencrypt"
"github.com/mholt/caddy/server"
"github.com/mholt/caddy/server"
)
)
...
@@ -33,8 +34,8 @@ func init() {
...
@@ -33,8 +34,8 @@ func init() {
flag
.
StringVar
(
&
config
.
Host
,
"host"
,
config
.
DefaultHost
,
"Default host"
)
flag
.
StringVar
(
&
config
.
Host
,
"host"
,
config
.
DefaultHost
,
"Default host"
)
flag
.
StringVar
(
&
config
.
Port
,
"port"
,
config
.
DefaultPort
,
"Default port"
)
flag
.
StringVar
(
&
config
.
Port
,
"port"
,
config
.
DefaultPort
,
"Default port"
)
flag
.
BoolVar
(
&
version
,
"version"
,
false
,
"Show version"
)
flag
.
BoolVar
(
&
version
,
"version"
,
false
,
"Show version"
)
flag
.
BoolVar
(
&
config
.
LetsEncryptAgree
,
"agree"
,
false
,
"Agree to Let's Encrypt Subscriber Agreement"
)
flag
.
BoolVar
(
&
letsencrypt
.
Agreed
,
"agree"
,
false
,
"Agree to Let's Encrypt Subscriber Agreement"
)
flag
.
StringVar
(
&
config
.
LetsEncryptEmail
,
"email"
,
""
,
"Email address to use for Let's Encrypt account
"
)
flag
.
StringVar
(
&
letsencrypt
.
DefaultEmail
,
"email"
,
""
,
"Default email address to use for Let's Encrypt transactions
"
)
}
}
func
main
()
{
func
main
()
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment