mirror of
https://github.com/go-acme/lego.git
synced 2024-12-27 03:32:05 +02:00
Make solvers configurable.
Allows selecting which solvers are available, and specifying options for them.
This commit is contained in:
parent
039b7c50dc
commit
b2c88d7a5d
@ -16,8 +16,13 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Logger is an optional custom logger.
|
||||
var Logger *log.Logger
|
||||
var (
|
||||
// DefaultSolvers is the set of solvers to use if none is given to NewClient.
|
||||
DefaultSolvers = []string{"http-01", "tls-sni-01"}
|
||||
|
||||
// Logger is an optional custom logger.
|
||||
Logger *log.Logger
|
||||
)
|
||||
|
||||
// logf writes a log entry. It uses Logger if not
|
||||
// nil, otherwise it uses the default log.Logger.
|
||||
@ -56,9 +61,12 @@ type Client struct {
|
||||
// the ACME directory located at caDirURL for the rest of its actions. It will
|
||||
// generate private keys for certificates of size keyBits. And, if the challenge
|
||||
// type requires it, the client will open a port at optPort to solve the challenge.
|
||||
// If optPort is blank, the port required by the spec will be used, but you must
|
||||
// forward the required port to optPort for the challenge to succeed.
|
||||
func NewClient(caDirURL string, user User, keyBits int, optPort string) (*Client, error) {
|
||||
//
|
||||
// If optSolvers is nil, the value of DefaultSolvers is used. If given explicitly,
|
||||
// it is a set of solver names to enable. The "http-01" and "tls-sni-01" solvers
|
||||
// take an optional TCP port to listen on after a colon, e.g. "http-01:80". If
|
||||
// the port is not specified, the port required by the spec will be used.
|
||||
func NewClient(caDirURL string, user User, keyBits int, optSolvers []string) (*Client, error) {
|
||||
privKey := user.GetPrivateKey()
|
||||
if privKey == nil {
|
||||
return nil, errors.New("private key was nil")
|
||||
@ -92,9 +100,31 @@ func NewClient(caDirURL string, user User, keyBits int, optPort string) (*Client
|
||||
// Add all available solvers with the right index as per ACME
|
||||
// spec to this map. Otherwise they won`t be found.
|
||||
solvers := make(map[string]solver)
|
||||
if optSolvers == nil {
|
||||
optSolvers = DefaultSolvers
|
||||
}
|
||||
for _, s := range optSolvers {
|
||||
ss := strings.SplitN(s, ":", 2)
|
||||
switch ss[0] {
|
||||
case "http-01":
|
||||
optPort := ""
|
||||
if len(ss) > 1 {
|
||||
optPort = ss[1]
|
||||
}
|
||||
solvers["http-01"] = &httpChallenge{jws: jws, validate: validate, optPort: optPort}
|
||||
|
||||
case "tls-sni-01":
|
||||
optPort := ""
|
||||
if len(ss) > 1 {
|
||||
optPort = ss[1]
|
||||
}
|
||||
solvers["tls-sni-01"] = &tlsSNIChallenge{jws: jws, validate: validate, optPort: optPort}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown solver: %s", s)
|
||||
}
|
||||
}
|
||||
|
||||
return &Client{directory: dir, user: user, jws: jws, keyBits: keyBits, solvers: solvers}, nil
|
||||
}
|
||||
|
||||
|
@ -27,8 +27,7 @@ func TestNewClient(t *testing.T) {
|
||||
w.Write(data)
|
||||
}))
|
||||
|
||||
caURL, optPort := ts.URL, "1234"
|
||||
client, err := NewClient(caURL, user, keyBits, optPort)
|
||||
client, err := NewClient(ts.URL, user, keyBits, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not create client: %v", err)
|
||||
}
|
||||
@ -47,6 +46,30 @@ func TestNewClient(t *testing.T) {
|
||||
if expected, actual := 2, len(client.solvers); actual != expected {
|
||||
t.Fatalf("Expected %d solver(s), got %d", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewClientOptPort(t *testing.T) {
|
||||
keyBits := 32 // small value keeps test fast
|
||||
key, err := rsa.GenerateKey(rand.Reader, keyBits)
|
||||
if err != nil {
|
||||
t.Fatal("Could not generate test key:", err)
|
||||
}
|
||||
user := mockUser{
|
||||
email: "test@test.com",
|
||||
regres: new(RegistrationResource),
|
||||
privatekey: key,
|
||||
}
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
data, _ := json.Marshal(directory{NewAuthzURL: "http://test", NewCertURL: "http://test", NewRegURL: "http://test", RevokeCertURL: "http://test"})
|
||||
w.Write(data)
|
||||
}))
|
||||
|
||||
optPort := "1234"
|
||||
client, err := NewClient(ts.URL, user, keyBits, []string{"http-01:" + optPort})
|
||||
if err != nil {
|
||||
t.Fatalf("Could not create client: %v", err)
|
||||
}
|
||||
|
||||
httpSolver, ok := client.solvers["http-01"].(*httpChallenge)
|
||||
if !ok {
|
||||
|
6
cli.go
6
cli.go
@ -74,9 +74,9 @@ func main() {
|
||||
Usage: "Directory to use for storing the data",
|
||||
Value: defaultPath,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "port",
|
||||
Usage: "Challenges will use this port to listen on. Please make sure to forward port 443 to this port on your machine. Otherwise use setcap on the binary",
|
||||
cli.StringSliceFlag{
|
||||
Name: "solvers, S",
|
||||
Usage: "Add an explicit solver for challenges. Solvers: \"http-01[:port]\", \"tls-sni-01[:port]\".",
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) {
|
||||
//TODO: move to account struct? Currently MUST pass email.
|
||||
acc := NewAccount(c.GlobalString("email"), conf)
|
||||
|
||||
client, err := acme.NewClient(c.GlobalString("server"), acc, conf.RsaBits(), conf.OptPort())
|
||||
client, err := acme.NewClient(c.GlobalString("server"), acc, conf.RsaBits(), conf.Solvers())
|
||||
if err != nil {
|
||||
logger().Fatal("Could not create client:", err)
|
||||
}
|
||||
|
@ -24,8 +24,8 @@ func (c *Configuration) RsaBits() int {
|
||||
return c.context.GlobalInt("rsa-key-size")
|
||||
}
|
||||
|
||||
func (c *Configuration) OptPort() string {
|
||||
return c.context.GlobalString("port")
|
||||
func (c *Configuration) Solvers() []string {
|
||||
return c.context.GlobalStringSlice("solvers")
|
||||
}
|
||||
|
||||
// ServerPath returns the OS dependent path to the data for a specific CA
|
||||
|
Loading…
Reference in New Issue
Block a user